ganjoorandroid/design/components/bundle.css
Claude ebbf737dac
Add the design system extracted from the app
design/ holds the tokens for all six themes, the type scale, spacing,
radii and sizes, the brand and usage guidelines, a guide and static
preview for each component, the logo and icons as SVG, and wireframes of
the tablet and foldable column layout.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RhmDdrN5hgWrgRcFLAMsV6
2026-10-07 14:06:52 +00:00

159 lines
14 KiB
CSS
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/* Ganjoor — static renditions of the app's Compose components. Values come from tokens.css. */
.gj { font-family: var(--font-naskh); color: var(--on-surface); background: var(--surface); }
.gj[lang="en"] { font-family: var(--font-libron); }
.gj *, .gj *::before, .gj *::after { box-sizing: border-box; }
.gj-icon { width: var(--icon); height: var(--icon); fill: currentColor; flex: none; display: block; }
.gj-icon-btn { width: var(--touch); height: var(--touch); border: 0; background: none; color: var(--on-surface-variant); border-radius: var(--radius-full); display: inline-flex; align-items: center; justify-content: center; cursor: pointer; padding: 0; }
.gj-icon-btn:hover { background: color-mix(in srgb, var(--on-surface-variant) 8%, transparent); }
.gj-icon-btn:focus-visible, .gj-text-btn:focus-visible, .gj-chip:focus-visible, .gj-card:focus-visible, .gj-row:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; }
/* Top app bar: 64px, surface, title-large; nav icon on-surface, actions on-surface-variant. */
.gj-topbar { height: 64px; display: flex; align-items: center; gap: var(--space-4); padding: 0 var(--space-4); background: var(--surface); }
.gj-topbar .gj-nav { color: var(--on-surface); }
.gj-topbar-title { flex: 1; min-width: 0; font-size: 22px; line-height: 28px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; padding-inline-start: var(--space-4); }
.gj-topbar-actions { display: flex; }
.gj-topbar .gj-on { color: var(--primary); }
/* Text button: primary label-large, pill, 40px. */
.gj-text-btn { height: 40px; padding: 0 12px; border: 0; background: none; border-radius: var(--radius-full); color: var(--primary); font: 500 14px/20px var(--font-naskh); letter-spacing: 0.1px; display: inline-flex; align-items: center; gap: var(--space-4); cursor: pointer; }
.gj[lang="en"] .gj-text-btn { font-family: var(--font-libron); }
.gj-text-btn .gj-icon { width: var(--icon-inline); height: var(--icon-inline); }
.gj-text-btn.is-neutral { color: var(--on-surface); }
/* Breadcrumbs: title-medium; ancestors primary and tappable, current on-surface, » separators muted. */
.gj-crumbs { display: flex; flex-wrap: wrap; align-items: center; font-size: 16px; line-height: 24px; font-weight: 500; }
.gj-crumbs a { color: var(--primary); text-decoration: none; cursor: pointer; }
.gj-crumbs .gj-sep { color: var(--on-surface-variant); white-space: pre; }
.gj-crumbs .gj-here { color: var(--on-surface); }
.gj-metre { font-size: 12px; line-height: 16px; letter-spacing: .4px; color: var(--on-surface-variant); }
/* Couplet: two hemistichs stacked; first to the start, second to the end. */
.gj-couplet { padding: var(--space-6) 0; }
.gj-verse { font-family: var(--font-naskh); font-size: 22px; line-height: 1.8; color: var(--on-surface); margin: 0; }
.gj-couplet.is-nastaliq .gj-verse { font-family: var(--font-nastaliq); line-height: 2.4; }
.gj-verse.is-first { text-align: start; }
.gj-verse.is-second { text-align: end; }
.gj-verse.is-centered { text-align: center; }
.gj-verse.is-prose { text-align: justify; }
.gj-couplet-summary { font-size: 12px; line-height: 16px; letter-spacing: .4px; color: var(--on-surface-variant); padding-top: var(--space-4); }
.gj-couplet-toggle { display: flex; justify-content: flex-end; }
.gj-couplet-toggle .gj-icon-btn { width: var(--touch-compact); height: var(--touch-compact); }
.gj-couplet-toggle .gj-icon { width: var(--icon-small); height: var(--icon-small); }
.gj-actions { display: flex; flex-wrap: wrap; gap: var(--space-8); }
/* Filter chips: 32px, radius-sm; selected = secondary-container with a check. */
.gj-chips { display: flex; flex-wrap: wrap; gap: var(--space-8); }
.gj-chip { height: 32px; padding: 0 16px; border-radius: var(--radius-sm); border: 1px solid var(--outline); background: transparent; color: var(--on-surface-variant); font: 500 14px/20px var(--font-naskh); letter-spacing: .1px; display: inline-flex; align-items: center; gap: var(--space-8); cursor: pointer; }
.gj[lang="en"] .gj-chip { font-family: var(--font-libron); }
.gj-chip[aria-pressed="true"] { background: var(--secondary-container); color: var(--on-secondary-container); border-color: transparent; padding-inline-start: 8px; }
.gj-chip .gj-icon { width: var(--icon-inline); height: var(--icon-inline); }
/* Poet portrait disc: secondary-container with the initial underneath the photo. */
.gj-portrait { border-radius: var(--radius-full); background: var(--secondary-container); color: var(--on-secondary-container); display: flex; align-items: center; justify-content: center; overflow: hidden; flex: none; position: relative; }
.gj-portrait img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.gj-portrait.is-row { width: var(--avatar-row); height: var(--avatar-row); font-size: 16px; }
.gj-portrait.is-card { width: var(--avatar-card); height: var(--avatar-card); font-size: 28px; line-height: 36px; }
/* Poet card: filled Card, radius-md, surface-container-highest, 12 padding, 8 gap. */
.gj-poet-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(var(--poet-grid-min), 1fr)); gap: var(--space-12); }
.gj-card { background: var(--surface-container-highest); color: var(--on-surface); border-radius: var(--radius-md); padding: var(--space-12); display: flex; flex-direction: column; align-items: center; gap: var(--space-8); cursor: pointer; }
.gj-name { font-size: 16px; line-height: 24px; font-weight: 500; letter-spacing: .15px; text-align: center; display: flex; align-items: center; gap: var(--space-4); }
.gj-pin { width: var(--icon-pin); height: var(--icon-pin); color: var(--primary); fill: currentColor; flex: none; }
/* List row: Material ListItem, 16 side padding, 56–72 tall. */
.gj-row { display: flex; align-items: center; gap: var(--space-16); min-height: 72px; padding: var(--space-8) var(--space-16); background: var(--surface); cursor: pointer; }
.gj-row-text { flex: 1; min-width: 0; }
.gj-row-trailing { display: flex; align-items: center; gap: var(--space-4); }
.gj-row-support { font-size: 14px; line-height: 20px; letter-spacing: .25px; color: var(--on-surface-variant); }
/* Download state, all in a 48px box so ticks and arrows line up. */
.gj-dl { width: var(--touch); height: var(--touch); display: inline-flex; align-items: center; justify-content: center; }
.gj-dl.is-saved { color: var(--downloaded); }
.gj-dl.is-idle { color: var(--on-surface-variant); }
.gj-ring { width: var(--icon-inline); height: var(--icon-inline); border-radius: 50%; border: var(--space-2) solid var(--surface-container-highest); border-top-color: var(--primary); }
/* Settings sheet pieces. */
.gj-sheet { background: var(--surface-container-low); border-radius: var(--radius-xl) var(--radius-xl) 0 0; padding: var(--space-8) var(--space-20) var(--space-32); display: flex; flex-direction: column; gap: var(--space-8); }
.gj-handle { width: 32px; height: 4px; border-radius: var(--radius-full); background: var(--on-surface-variant); opacity: .4; margin: var(--space-8) auto var(--space-8); }
.gj-label { font-size: 14px; line-height: 20px; font-weight: 500; letter-spacing: .1px; color: var(--primary); padding-top: var(--space-12); }
.gj-toggle { display: flex; align-items: center; gap: var(--space-16); padding-top: var(--space-12); }
.gj-toggle-text { flex: 1; }
.gj-toggle-title { font-size: 16px; line-height: 24px; color: var(--on-surface); }
.gj-toggle-note { font-size: 12px; line-height: 16px; letter-spacing: .4px; color: var(--on-surface-variant); }
.gj-switch { width: 52px; height: 32px; border-radius: var(--radius-full); border: 2px solid var(--outline); background: var(--surface-container-highest); position: relative; flex: none; cursor: pointer; padding: 0; }
.gj-switch::after { content: ""; position: absolute; top: 50%; inset-inline-start: 6px; width: 16px; height: 16px; margin-top: -8px; border-radius: 50%; background: var(--outline); }
.gj-switch[aria-checked="true"] { background: var(--primary); border-color: var(--primary); }
.gj-switch[aria-checked="true"]::after { inset-inline-start: auto; inset-inline-end: 2px; width: 24px; height: 24px; margin-top: -12px; background: var(--on-primary); }
/* Bottom search bar: tonal surface, outlined field. */
.gj-searchbar { background: var(--surface-tonal-3); padding: var(--space-8) var(--space-12); }
.gj-field { height: 56px; border: 1px solid var(--outline); border-radius: var(--radius-xs); display: flex; align-items: center; gap: var(--space-16); padding: 0 var(--space-12); color: var(--on-surface-variant); font-size: 16px; line-height: 24px; letter-spacing: .5px; }
.gj-search-poems { display: flex; align-items: center; gap: var(--space-16); min-height: 56px; padding: 0 var(--space-16); color: var(--on-surface); }
.gj-search-poems .gj-icon { color: var(--primary); }
.gj-divider { height: 1px; background: var(--outline-variant); border: 0; margin: 0; }
.gj-ai-note { font-size: 11px; line-height: 16px; font-weight: 500; letter-spacing: .5px; color: var(--primary); padding-top: var(--space-12); }
.gj-summary { font-size: 14px; line-height: 20px; letter-spacing: .25px; color: var(--on-surface-variant); }
/* ── Large screens: ColumnBrowser (tablets, unfolded foldables; width ≥ 600) ──
Column browser in RTL: poets rail on the far right, then books, then chapters / poems,
and the open poem fills what is left on the left. */
.gj-ts { display: flex; height: 100%; overflow: hidden; background: var(--surface); }
.gj-ts-home { flex: 1; min-width: 0; display: flex; flex-direction: column; }
.gj-ts.is-split .gj-ts-home { display: none; }
.gj-ts-scroll { overflow-y: auto; min-height: 0; overscroll-behavior: contain; }
.gj-ts-cols { display: none; flex: none; height: 100%; }
.gj-ts.is-split .gj-ts-cols { display: flex; }
.gj-ts-col { flex: none; width: 224px; display: flex; flex-direction: column; min-height: 0; border-inline-end: 1px solid var(--outline-variant); background: var(--surface-container-low); transition: width 300ms cubic-bezier(.2,0,0,1); }
.gj-ts-col.is-new { animation: gj-ts-in 400ms cubic-bezier(.05,.7,.1,1) both; }
/* Columns narrow as you go deeper: the newest list is widest, older ones give their room to the poem. */
.gj-ts-col[data-dist="1"] { width: 168px; }
.gj-ts-col[data-dist="2"] { width: 132px; }
.gj-ts-col[data-dist="1"] .gj-ts-item, .gj-ts-col[data-dist="2"] .gj-ts-item { font-size: 14px; line-height: 20px; padding: var(--space-8); display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
.gj-ts-col[data-dist="1"] .gj-ts-item small, .gj-ts-col[data-dist="2"] .gj-ts-item small, .gj-ts-col[data-dist="1"] .gj-ts-item::after, .gj-ts-col[data-dist="2"] .gj-ts-item::after { display: none; }
.gj-ts-col[data-dist="1"] .gj-ts-colhead, .gj-ts-col[data-dist="2"] .gj-ts-colhead { padding: 0 var(--space-8); }
.gj-ts-col[data-dist="1"] .gj-ts-colhead b, .gj-ts-col[data-dist="2"] .gj-ts-colhead b { font-size: 14px; line-height: 20px; }
.gj-ts-col.is-rail { width: 96px; background: var(--surface-container); }
.gj-ts.is-deep .gj-ts-col.is-rail { width: 80px; }
.gj-ts.is-deep .gj-ts-poet .gj-portrait { width: 44px; height: 44px; font-size: 18px; }
.gj-ts-poet { overflow-wrap: anywhere; }
@keyframes gj-ts-in { from { opacity: 0; transform: translateX(-32px); } }
.gj-ts-col.is-rail.is-arriving { animation-name: gj-ts-rail; }
@keyframes gj-ts-rail { from { width: 100vw; } }
.gj-ts-colhead { flex: none; min-height: 56px; display: flex; flex-direction: column; justify-content: center; padding: 0 var(--space-16); border-bottom: 1px solid var(--outline-variant); }
.gj-ts-colhead small { color: var(--on-surface-variant); font: 500 11px/16px var(--font-naskh); letter-spacing: .5px; }
.gj-ts-colhead b { color: var(--on-surface); font: 500 16px/24px var(--font-naskh); overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }
.gj-ts-list { padding: var(--space-8); flex: 1; }
/* Poets rail: portrait with the name under it. */
.gj-ts-poet { display: flex; flex-direction: column; align-items: center; gap: var(--space-4); width: 100%; padding: var(--space-8) var(--space-4); border: 0; background: none; border-radius: var(--radius-md); color: var(--on-surface); font: 500 12px/16px var(--font-naskh); letter-spacing: .5px; text-align: center; cursor: pointer; }
.gj-ts-poet .gj-portrait { width: 56px; height: 56px; font-size: 22px; }
.gj-ts-poet[aria-current="true"] { background: var(--secondary-container); color: var(--on-secondary-container); }
.gj-ts-poet[aria-current="true"] .gj-portrait { outline: 2px solid var(--primary); outline-offset: 2px; }
/* Book / chapter / poem rows. */
.gj-ts-item { display: block; width: 100%; min-height: 48px; padding: var(--space-8) var(--space-12); border: 0; background: none; color: var(--on-surface); font: 400 16px/24px var(--font-naskh); text-align: start; cursor: pointer; border-radius: var(--radius-md); }
.gj-ts-item small { display: block; color: var(--on-surface-variant); font-size: 12px; line-height: 16px; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }
.gj-ts-item:hover, .gj-ts-poet:hover { background: color-mix(in srgb, var(--on-surface) 6%, transparent); }
.gj-ts-item[aria-current="true"] { background: var(--secondary-container); color: var(--on-secondary-container); }
.gj-ts-item[aria-current="true"] small { color: var(--on-secondary-container); }
.gj-ts-item.has-kids::after { content: "‹"; float: inline-end; color: var(--on-surface-variant); }
/* Focus mode: the columns fold away and the poem takes the whole width, still centred. */
.gj-ts.is-focus .gj-ts-cols { display: none; }
.gj-ts-toggle[aria-pressed="false"] { color: var(--primary); }
/* The open work. */
.gj-ts-main { flex: 1; min-width: 0; display: flex; flex-direction: column; animation: gj-ts-in 400ms cubic-bezier(.05,.7,.1,1) both; }
.gj-ts-content { flex: 1; padding: var(--space-8) var(--space-32) var(--space-32); }
.gj-ts-measure { max-width: 680px; margin-inline: auto; }
.gj-ts-main { container-type: inline-size; }
/* Hemistichs side by side only when the poem column has room; otherwise they stack as on a phone. */
.gj-ts .gj-couplet.is-wide .gj-verse.is-first { text-align: start; }
.gj-ts .gj-couplet.is-wide .gj-verse.is-second { text-align: end; }
@container (min-width: 640px) {
.gj-ts .gj-couplet.is-wide { display: grid; grid-template-columns: 1fr 1fr; column-gap: var(--space-32); align-items: baseline; }
}
.gj-ts-books { display: grid; grid-template-columns: repeat(auto-fill, minmax(180px, 1fr)); gap: var(--space-12); margin-top: var(--space-16); }
.gj-ts-books .gj-card { align-items: flex-start; text-align: start; }