# RosterElf Website - AI Context This file contains a structured representation of the RosterElf website content, designed for easy consumption by AI systems, chatbots, and automated tools. ## About This File **Purpose**: Provide AI agents with comprehensive, structured access to RosterElf's website content including features, guides, blog posts, and documentation. **Format**: Markdown with file paths and line numbers - Each section begins with: ## File: path/to/file - Line numbers are prefixed to each line for reference - Content is organized by topic and importance **Usage**: This file is read-only. Use file paths to navigate between sections. Changes should be made to the original website files, not this packed version. **Last Updated**: 2026-02-26 --- # Files ## File: src/components/comparison/ComparisonHelpers.astro ````astro 1: --- 2: /** 3: * Reusable components for comparison pages 4: * Import these in your comparison page content 5: */ 6: import { Check, X } from 'lucide-astro' 7: 8: // Export props interfaces for use in pages 9: export interface ComparisonTableRow { 10: feature: string 11: platform1: string | boolean | number 12: platform2: string | boolean | number 13: } 14: 15: interface Props { 16: // You can add shared props here if needed 17: } 18: --- 19: 20: ```` ## File: src/components/AgedCareAwardCalculator.astro ````astro 1: --- 2: // Aged Care Award Rate Calculator Component 3: // Data from 2025/26 Aged Care Award rates (MA000018) 4: 5: import { AlertTriangle, FileText, Clock, CheckCircle, ChevronDown, User, Calculator } from 'lucide-astro' 6: import TrialButton from './TrialButton.astro' 7: 8: const ratesData = { 9: // General classification (Levels 1-7) - effective 1 July 2025 10: general_permanent: { 11: 'Level 1': 26.51, 12: 'Level 2': 27.56, 13: 'Level 3': 28.62, 14: 'Level 4': 28.96, 15: 'Level 5': 29.94, 16: 'Level 6': 31.55, 17: 'Level 7': 32.12, 18: }, 19: general_casual: { 20: 'Level 1': 33.14, // 26.51 × 1.25 21: 'Level 2': 34.45, // 27.56 × 1.25 22: 'Level 3': 35.78, // 28.62 × 1.25 23: 'Level 4': 36.2, // 28.96 × 1.25 24: 'Level 5': 37.43, // 29.94 × 1.25 25: 'Level 6': 39.44, // 31.55 × 1.25 26: 'Level 7': 40.15, // 32.12 × 1.25 27: }, 28: // Direct care classification (Levels 1-6) - effective 1 October 2025 29: directcare_permanent: { 30: 'Level 1': 31.13, 31: 'Level 2': 32.86, 32: 'Level 3': 34.59, 33: 'Level 4': 35.97, 34: 'Level 5': 37.35, 35: 'Level 6': 38.74, 36: }, 37: directcare_casual: { 38: 'Level 1': 38.91, // 31.13 × 1.25 39: 'Level 2': 41.08, // 32.86 × 1.25 40: 'Level 3': 43.24, // 34.59 × 1.25 41: 'Level 4': 44.96, // 35.97 × 1.25 42: 'Level 5': 46.69, // 37.35 × 1.25 43: 'Level 6': 48.43, // 38.74 × 1.25 44: }, 45: } 46: 47: // Fixed award rules - non-editable, shows how the award works 48: const awardRules = [ 49: { 50: id: 'ordinary', 51: name: 'Ordinary hours (Mon-Fri)', 52: days: ['MON', 'TUE', 'WED', 'THU', 'FRI'], 53: startTime: '06:00', 54: endTime: '18:00', 55: penaltyMultiplier: { permanent: 1.0, casual: 1.25 }, // Casual gets 25% loading 56: }, 57: { 58: id: 'evening', 59: name: 'Evening shift allowance', 60: days: ['MON', 'TUE', 'WED', 'THU', 'FRI'], 61: startTime: '18:00', 62: endTime: '00:00', 63: penaltyMultiplier: { permanent: 1.15, casual: 1.4375 }, // 15% allowance + 25% casual loading (1.15 × 1.25) 64: }, 65: { 66: id: 'night', 67: name: 'Night shift allowance', 68: days: ['MON', 'TUE', 'WED', 'THU', 'FRI'], 69: startTime: '00:00', 70: endTime: '06:00', 71: penaltyMultiplier: { permanent: 1.15, casual: 1.4375 }, // 15% allowance + 25% casual loading (1.15 × 1.25) 72: }, 73: { 74: id: 'saturday', 75: name: 'Saturday (all day)', 76: days: ['SAT'], 77: startTime: '00:00', 78: endTime: '00:00', 79: penaltyMultiplier: { permanent: 1.5, casual: 1.75 }, // Weekend rates substitute for casual loading 80: }, 81: { 82: id: 'sunday', 83: name: 'Sunday (all day)', 84: days: ['SUN'], 85: startTime: '00:00', 86: endTime: '00:00', 87: penaltyMultiplier: { permanent: 1.75, casual: 2.0 }, // Weekend rates substitute for casual loading 88: }, 89: { 90: id: 'publicholiday', 91: name: 'Public holiday', 92: days: ['HOL'], 93: startTime: '00:00', 94: endTime: '00:00', 95: penaltyMultiplier: { permanent: 2.5, casual: 2.75 }, // Public holiday rate substitutes for casual loading 96: }, 97: ] 98: --- 99: 100:
101:
102:
AWARD RATE ESTIMATOR
103:

See how RosterElf interprets the Aged Care Award

104:

105: This is an educational example showing how the Aged Care Award penalty rates work. It demonstrates how RosterElf automatically calculates correct pay rates based on classification level, 106: employment type, and shift times. 107:

108:
109: 110: 111:
112:
113: 114:
115: Important: This is an estimator for demonstration purposes only. Do not use these calculations for actual payroll without verifying against the 116: official Fair Work pay guide 119: and consulting your Award obligations. 120:
121:
122:
123: 124: 125:
126:
127: 128:
129: 130:
131:
132: 133:
134: 141:
142:
143: 144: 145:
146: 147:
148:
149: 150:
151: 158:
159:
160: 161: 162:
163: 164:
165:
166: 167:
168: 174:
175:
176:
177:
178: 179: 180:
181:
182:
183:
Base ordinary rate
184:
Mon-Fri, standard hours
185:
186:
187:
188: $ 189: 26.51 190: /hr 191:
192:
193:
194:
195: 196: 197:
198:

199: 200: Aged Care Award penalty rates 201:

202: 203:
204: 205:
206:
207: 208: 209:
210:

211: 212: Example weekly cost (38 hours) 213:

214: 215:
216: 217:
218: 219:
220: Example total: 221: $1,007.38 222:
223:
224: 225: 226:
227:
228:
229: 230:
231:

Example only - not for payroll use

232:

This is a demonstration of how RosterElf calculates award-compliant rates.

233:
234:
235: 245:
246: 247:
248:
249:
250:

The actual cost for your employees will depend on:

251: 252:
    253:
  • Their specific classification level and employment type
  • 254:
  • Actual hours worked and shift times
  • 255:
  • Any additional allowances, overtime, or enterprise agreement provisions
  • 256:
  • Current award rates (which change annually in July)
  • 257:
258: 259:
260:

Calculator Limitation

261:

262: This calculator displays simplified time-based penalties (e.g., "evening 6pm–midnight") for demonstration purposes. The actual Aged Care Award has more complex shift allowance rules 263: based on when shifts start, not just the hours worked. Always verify penalty rates with the official Fair Work pay guide or PACT tool for your specific shift patterns. 264:

265:
266: 267:

For accurate payroll calculations, always:

268: 269:
    270:
  1. 271: Verify current rates with the official Fair Work pay guide 277:
  2. 278:
  3. Confirm your employees' correct award coverage and classification
  4. 279:
  5. Use award interpretation software or consult a payroll professional
  6. 280:
  7. Review your specific enterprise agreement (if applicable)
  8. 281:
282: 283:

Do not rely on this example for actual wage payments.

284:
285:
286:
287:
288: 289: 290:
291: 292:
293:

Stop calculating penalty rates manually

294:

Let RosterElf handle award compliance automatically

295: 296:

297: Manual award calculations are time-consuming and error-prone. One mistake can lead to underpayments, compliance issues, and Fair Work penalties. RosterElf's award interpretation engine does 298: the work for you. 299:

300: 301:
302: 303:
304: 305:
306: 307: 308: No credit card required 309: 310: 311: 312: Full access 313: 314: 315: 316: 24/7 support 317: 318:
319:
320: 321: 322:
323:

How RosterElf automates award calculations

324: 325:
326: 327:
328:
329:
1
330: 331:
332:
Create pay templates
333:

334: Create pay templates for each classification level by adding award-compliant base rates and penalty multipliers. Once configured, RosterElf automatically applies the correct template to 335: each shift based on the employee's classification, shift timing, and employment type. 336:

337: Award interpretation → 338:
339: 340: 341:
342:
343:
2
344: 345:
346:
Define rate rules
347:

348: Configure when different penalty rates apply (evenings, weekends, public holidays). The system automatically detects which rate to use based on shift times and days. 349:

350: Penalty rates guide → 351:
352: 353: 354:
355:
356:
3
357: 358:
359:
Auto-apply to shifts
360:

361: Every rostered shift automatically calculates the correct pay rate based on the employee's classification, employment type, and shift timing. No manual work required. 362:

363: Payroll integration → 364:
365:
366: 367: 368:
369:

Learn more:

370: 377:
378:
379:
380:
381: 382: 651: 652: ```` ## File: src/components/AwardRatesCallout.astro ````astro 1: --- 2: import { ArrowRight, BookOpen } from 'lucide-astro' 3: import { getAwardRate } from '../data/industryMappings' 4: 5: interface Props { 6: industry: string 7: background?: 'white' | 'primary' 8: } 9: 10: const { industry, background = 'primary' } = Astro.props 11: 12: const awardRate = getAwardRate(industry) 13: 14: const bgClass = background === 'white' ? 'bg-white' : 'bg-primary-100' 15: const cardBgClass = background === 'white' ? 'bg-primary-50' : 'bg-white' 16: --- 17: 18: { 19: awardRate && ( 20:
21:
22: 29:
30:
31: 32:
33:
34: Award rates guide 35:

{awardRate.name}

36:

{awardRate.description}

37:
38:
39:
40: View guide 41: 42:
43:
44:
45:
46: ) 47: } ```` ## File: src/components/BlogResourceCards.astro ````astro 1: --- 2: import { ArrowRight } from 'lucide-astro' 3: import { readFile } from 'node:fs/promises' 4: import { join } from 'node:path' 5: 6: interface BlogPost { 7: title: string 8: excerpt: string 9: href: string 10: image: string 11: category: string 12: readTime: string 13: } 14: 15: interface Props { 16: chip?: string 17: title?: string 18: description?: string 19: posts?: BlogPost[] 20: background?: 'primary' | 'white' 21: } 22: 23: const defaultPosts: BlogPost[] = [ 24: { 25: title: 'Rostering strategy planning for the new year', 26: excerpt: 'Plan your rostering strategy for the new year. Review performance, set goals, forecast capacity, and implement improvements.', 27: href: '/blog/rostering-strategy-planning', 28: image: '/images/stock/unsplash-1600880292089-90a7e086ee0c.webp', 29: category: 'Rostering & Scheduling', 30: readTime: '9 min read', 31: }, 32: { 33: title: 'Fair and cost-effective rostering for Australian SMEs', 34: excerpt: 'Learn how Australian businesses build fair, cost-effective rosters while staying award compliant.', 35: href: '/blog/fair-cost-effective-employee-rostering-australia', 36: image: '/images/stock/unsplash-1553484771-898ed465e931.webp', 37: category: 'Rostering & Scheduling', 38: readTime: '9 min read', 39: }, 40: { 41: title: 'Reviewing rostering KPIs from the past year', 42: excerpt: 'Review rostering KPIs to improve next year. Analyse labour costs, roster accuracy, overtime rates, and set realistic targets.', 43: href: '/blog/rostering-kpis-review', 44: image: '/images/stock/unsplash-1573165231977-3f0e27806045.webp', 45: category: 'Rostering & Scheduling', 46: readTime: '9 min read', 47: }, 48: ] 49: 50: /** 51: * Check if a blog post has a future premiere date 52: */ 53: async function hasFuturePremiereDate(blogSlug: string): Promise { 54: try { 55: const filePath = join(process.cwd(), 'src/pages/blog', `${blogSlug}.astro`) 56: const content = await readFile(filePath, 'utf-8') 57: 58: // Extract premiere date from content 59: const premiereDateMatch = content.match(/premiereDate\s*=\s*['"]([^'"]+)['"]/) 60: if (!premiereDateMatch) return false 61: 62: const premiereDate = new Date(premiereDateMatch[1]) 63: const now = new Date() 64: 65: // Compare dates at midnight 66: now.setHours(0, 0, 0, 0) 67: premiereDate.setHours(0, 0, 0, 0) 68: 69: return premiereDate > now 70: } catch { 71: // If file doesn't exist or can't be read, assume it's not a blog post or is published 72: return false 73: } 74: } 75: 76: /** 77: * Filter out blog posts with future premiere dates 78: */ 79: async function filterPublishedPosts(posts: BlogPost[]): Promise { 80: const results = await Promise.all( 81: posts.map(async (post) => { 82: // Only check blog posts (href starts with /blog/) 83: if (!post.href.startsWith('/blog/')) return { post, isPublished: true } 84: 85: // Extract slug from href 86: const slug = post.href.replace('/blog/', '') 87: const isFuture = await hasFuturePremiereDate(slug) 88: 89: return { post, isPublished: !isFuture } 90: }) 91: ) 92: 93: return results.filter((r) => r.isPublished).map((r) => r.post) 94: } 95: 96: const { 97: chip = 'RESOURCES', 98: title = 'Learn more about rostering', 99: description = 'Guides and articles to help you master staff scheduling and compliance.', 100: posts = defaultPosts, 101: background = 'white', 102: } = Astro.props 103: 104: // Filter out unpublished posts 105: const publishedPosts = await filterPublishedPosts(posts) 106: 107: const bgClass = background === 'primary' ? 'bg-primary-100' : 'bg-white' 108: --- 109: 110:
111:
112:
113: {chip} 114:

{title}

115:

{description}

116:
117: 118: 140: 141: View all articles → 142:
143:
```` ## File: src/components/BookCallModal.astro ````astro 1: --- 2: // Book a Call Modal - lets users choose between demo (sales) or support calls 3: --- 4: 5: 88: 89: ```` ## File: src/components/BookmarkModal.astro ````astro 1: --- 2: /** 3: * BookmarkModal Component 4: * 5: * Reusable bookmark prompt modal for free tools pages. 6: * Shows keyboard shortcuts to bookmark the page. 7: * 8: * Usage: 9: * 1. Import and add to your page 10: * 2. Add class="bookmark-btn" to any button that should trigger the modal 11: * 12: * Props: 13: * - showCard: Show a card section with bookmark button (like free-roster-tool) 14: * - message: Custom message for the modal 15: * - cardTitle: Title for the card section 16: * - cardSubtitle: Subtitle for the card section 17: */ 18: 19: import { Bookmark } from 'lucide-astro' 20: 21: interface Props { 22: /** Custom message explaining why to bookmark */ 23: message?: string 24: /** Show a card section with bookmark button */ 25: showCard?: boolean 26: /** Card title */ 27: cardTitle?: string 28: /** Card subtitle */ 29: cardSubtitle?: string 30: } 31: 32: const { 33: message = 'Bookmark this page to return anytime — your data is saved in your browser.', 34: showCard = false, 35: cardTitle = 'Bookmark this page', 36: cardSubtitle = 'Save this page to your bookmarks for quick access anytime.', 37: } = Astro.props 38: --- 39: 40: { 41: showCard && ( 42:
43:
44:
45:
46: 47:
48:
49:

{cardTitle}

50:

{cardSubtitle}

51:
52: 56:
57:
58:
59: ) 60: } 61: 62: 63: 96: 97: ```` ## File: src/components/Breadcrumb.astro ````astro 1: --- 2: import { ChevronRight } from 'lucide-astro' 3: 4: interface BreadcrumbItem { 5: label: string 6: href: string 7: } 8: 9: interface Props { 10: items: BreadcrumbItem[] 11: variant?: 'default' | 'highlighted' | 'highlighted-white' 12: } 13: 14: const { items, variant = 'default' } = Astro.props 15: 16: // Prefix hrefs with /uk when rendered on a UK page 17: const isUK = Astro.url.pathname.startsWith('/uk') 18: const prefixHref = (href: string) => { 19: if (!isUK || !href.startsWith('/') || href.startsWith('/uk')) return href 20: return href === '/' ? '/uk' : '/uk' + href 21: } 22: const prefixedItems = items.map((item) => ({ ...item, href: prefixHref(item.href) })) 23: 24: // Separate the last item (current page) from the rest 25: const navigationItems = prefixedItems.slice(0, -1) 26: const currentItem = prefixedItems[prefixedItems.length - 1] 27: 28: const bgClass = variant === 'highlighted' ? 'bg-primary-100' : variant === 'highlighted-white' ? 'bg-white' : '' 29: 30: // Generate BreadcrumbList JSON-LD schema 31: const breadcrumbSchema = { 32: '@context': 'https://schema.org', 33: '@type': 'BreadcrumbList', 34: itemListElement: prefixedItems.map((item, index) => ({ 35: '@type': 'ListItem', 36: position: index + 1, 37: name: item.label, 38: item: item.href.startsWith('http') ? item.href : `https://www.rosterelf.com${item.href}`, 39: })), 40: } 41: --- 42: 43: ```` ## File: src/components/DownloadableChecklist.astro ````astro 1: --- 2: /** 3: * DownloadableChecklist - Printable compliance checklist component 4: * 5: * Creates a printable/downloadable checklist for NSW LSL compliance 6: * Users can print directly from browser or save as PDF 7: */ 8: 9: interface Props { 10: title?: string 11: description?: string 12: background?: 'primary' | 'white' 13: } 14: 15: const { 16: title = 'NSW Long Service Leave Compliance Checklist', 17: description = "Print or save this checklist to ensure you're meeting all NSW LSL compliance requirements.", 18: background = 'white', 19: } = Astro.props 20: 21: const bgClass = background === 'primary' ? 'bg-primary-100' : 'bg-white' 22: --- 23: 24:
25:
26:
27: FREE CHECKLIST 28:

{title}

29:

{description}

30: 40:
41: 42: 43:
44: 45: 49: 50: 51:
52:

53: 54: 59: 60: Initial Setup 61:

62:
63: 70: 71: 78: 79: 86: 87: 94:
95:
96: 97: 98:
99:

100: 101: 106: 107: Record Keeping & Tracking 108:

109:
110: 117: 118: 125: 126: 133: 134: 141: 142: 149:
150:
151: 152: 153:
154:

155: 156: 157: 158: Ongoing Compliance 159:

160:
161: 168: 169: 176: 177: 184: 185: 192: 193: 200: 201: 208:
209:
210: 211: 212:
213:

214: 215: 220: 221: Termination & Payout 222:

223:
224: 231: 232: 239: 240: 247: 248: 255:
256:
257: 258: 259:
260:
261: Checklist Progress 262: 0 of 23 completed 263:
264:
265:
266:
267:
268:
269:
270:
271: 272: 318: 319: ```` ## File: src/components/ElectricalAwardCalculator.astro ````astro 1: --- 2: // Electrical Award Rate Calculator Component 3: // Data from 2025 Electrical, Electronic and Communications Contracting Award rates 4: 5: import { AlertTriangle, FileText, Clock, CheckCircle, ChevronDown, User, Calculator } from 'lucide-astro' 6: import TrialButton from './TrialButton.astro' 7: 8: const ratesData = { 9: permanent: { 10: 'Grade 1': 25.99, 11: 'Grade 2': 26.49, 12: 'Grade 3': 27.34, 13: 'Grade 4': 28.19, 14: 'Grade 5': 29.74, 15: 'Grade 6': 30.63, 16: 'Grade 7': 32.3, 17: 'Grade 8': 33.86, 18: 'Grade 9': 34.52, 19: 'Grade 10': 37.17, 20: }, 21: casual: { 22: 'Grade 1': 32.49, 23: 'Grade 2': 33.11, 24: 'Grade 3': 34.18, 25: 'Grade 4': 35.24, 26: 'Grade 5': 37.18, 27: 'Grade 6': 38.29, 28: 'Grade 7': 40.38, 29: 'Grade 8': 42.33, 30: 'Grade 9': 43.15, 31: 'Grade 10': 46.46, 32: }, 33: } 34: 35: // Fixed award rules - non-editable, shows how the award works 36: const awardRules = [ 37: { 38: id: 'ordinary', 39: name: 'Ordinary hours (Mon-Sat)', 40: days: ['MON', 'TUE', 'WED', 'THU', 'FRI', 'SAT'], 41: startTime: '07:00', 42: endTime: '17:00', 43: penaltyMultiplier: { permanent: 1.0, casual: 1.25 }, 44: }, 45: { 46: id: 'sunday', 47: name: 'Sunday', 48: days: ['SUN'], 49: startTime: '00:00', 50: endTime: '00:00', 51: penaltyMultiplier: { permanent: 2.0, casual: 2.5 }, 52: }, 53: { 54: id: 'publicholiday', 55: name: 'Public holiday', 56: days: ['HOL'], 57: startTime: '00:00', 58: endTime: '00:00', 59: penaltyMultiplier: { permanent: 2.5, casual: 3.125 }, 60: }, 61: ] 62: --- 63: 64:
65:
66:
AWARD RATE ESTIMATOR
67:

See how RosterElf interprets the Electrical Award

68:

69: This is an educational example showing how the Electrical Award penalty rates work. It demonstrates how RosterElf automatically calculates correct pay rates based on classification grade, 70: employment type, and shift times. 71:

72:
73: 74: 75:
76:
77: 78:
79: Important: This is an estimator for demonstration purposes only. Do not use these calculations for actual payroll without verifying against the 80: official Fair Work pay guide 86: and consulting your Award obligations. 87:
88:
89:
90: 91: 92:
93:
94: 95:
96: 97:
98:
99: 100:
101: 108:
109:
110: 111: 112:
113: 114:
115:
116: 117:
118: 133:
134:
135:
136:
137: 138: 139:
140:
141:
142:
Base ordinary rate
143:
Mon-Sat, standard hours
144:
145:
146:
147: $ 148: 29.74 149: /hr 150:
151:
152:
153:
154: 155: 156:
157:

158: 159: Electrical Award penalty rates 160:

161: 162:
163: 164:
165:
166: 167: 168:
169:

170: 171: Example weekly cost (38 hours) 172:

173: 174:
175: 176:
177: 178:
179: Example total: 180: $1,130.12 181:
182:
183: 184: 185:
186:
187:
188: 189:
190:

Example only - not for payroll use

191:

This is a demonstration of how RosterElf calculates award-compliant rates.

192:
193:
194: 204:
205: 206:
207:
208:
209:

The actual cost for your employees will depend on:

210: 211:
    212:
  • Their specific classification grade and employment type
  • 213:
  • Actual hours worked and shift times
  • 214:
  • Any additional allowances (licence, leading hand, tool, travel), overtime, or enterprise agreement provisions
  • 215:
  • Current award rates (which change annually in July)
  • 216:
217: 218:

For accurate payroll calculations, always:

219: 220:
    221:
  1. 222: Verify current rates with the official Fair Work pay guide 228:
  2. 229:
  3. Confirm your employees' correct award coverage and classification
  4. 230:
  5. Use award interpretation software or consult a payroll professional
  6. 231:
  7. Review your specific enterprise agreement (if applicable)
  8. 232:
233: 234:

Do not rely on this example for actual wage payments.

235:
236:
237:
238:
239: 240: 241:
242: 243:
244:

Stop calculating award rates manually

245:

Let RosterElf handle award compliance automatically

246: 247:

248: Manual award calculations are time-consuming and error-prone. One mistake can lead to underpayments, compliance issues, and Fair Work penalties. RosterElf's award interpretation engine does 249: the work for you. 250:

251: 252:
253: 254:
255: 256:
257: 258: 259: No credit card required 260: 261: 262: 263: Full access 264: 265: 266: 267: 24/7 support 268: 269:
270:
271: 272: 273:
274:

How RosterElf automates award calculations

275: 276:
277: 278:
279:
280:
1
281: 282:
283:
Create pay templates
284:

285: Create pay templates for each classification grade by adding award-compliant base rates and penalty multipliers. Once configured, RosterElf automatically applies the correct template to 286: each shift based on the employee's classification, shift timing, and employment type. 287:

288: Award interpretation → 289:
290: 291: 292:
293:
294:
2
295: 296:
297:
Define rate rules
298:

299: Configure when different penalty rates apply (Sundays, public holidays). The system automatically detects which rate to use based on shift times and days. 300:

301: Penalty rates guide → 302:
303: 304: 305:
306:
307:
3
308: 309:
310:
Auto-apply to shifts
311:

312: Every rostered shift automatically calculates the correct pay rate based on the employee's classification, employment type, and shift timing. No manual work required. 313:

314: Payroll integration → 315:
316:
317: 318: 319:
320:

Learn more:

321: 328:
329:
330:
331:
332: 333: 557: 558: ```` ## File: src/components/EmploymentLawCrossReference.astro ````astro 1: --- 2: import { MapPin, Scale, DollarSign, ArrowRight } from 'lucide-astro' 3: 4: interface Props { 5: currentSlug: string 6: maxItems?: number 7: background?: 'white' | 'primary' 8: } 9: 10: const { currentSlug, maxItems = 6, background = 'primary' } = Astro.props 11: 12: // All employment law pages data 13: const allEmploymentLawPages = [ 14: { 15: slug: 'sa-long-service-leave', 16: title: 'SA Long Service Leave', 17: description: '13 weeks after 10 years, pro-rata at 7 years, payment calculations', 18: category: 'Long Service Leave', 19: state: 'SA', 20: href: '/guides/employment-law/sa-long-service-leave', 21: icon: MapPin, 22: }, 23: { 24: slug: 'victoria-long-service-leave', 25: title: 'Victoria Long Service Leave', 26: description: '7-year eligibility, progressive entitlement, portable schemes', 27: category: 'Long Service Leave', 28: state: 'VIC', 29: href: '/guides/employment-law/victoria-long-service-leave', 30: icon: MapPin, 31: }, 32: { 33: slug: 'qld-long-service-leave', 34: title: 'QLD Long Service Leave', 35: description: '10-year entitlement, 7-year pro-rata, QLeave portable schemes', 36: category: 'Long Service Leave', 37: state: 'QLD', 38: href: '/guides/employment-law/qld-long-service-leave', 39: icon: MapPin, 40: }, 41: { 42: slug: 'victoria-workers-compensation', 43: title: "Victoria Workers' Compensation", 44: description: 'WorkCover claims, weekly payments (PIAWE), treatment expenses', 45: category: "Workers' Compensation", 46: state: 'VIC', 47: href: '/guides/employment-law/victoria-workers-compensation', 48: icon: Scale, 49: }, 50: { 51: slug: 'workers-compensation-sa', 52: title: "SA Workers' Compensation", 53: description: 'ReturnToWorkSA claims, income support, return to work planning', 54: category: "Workers' Compensation", 55: state: 'SA', 56: href: '/guides/employment-law/workers-compensation-sa', 57: icon: Scale, 58: }, 59: { 60: slug: 'nsw-payroll-tax', 61: title: 'NSW Payroll Tax', 62: description: '$1.2M threshold, 5.45% rate, grouping rules, monthly compliance', 63: category: 'Payroll Tax', 64: state: 'NSW', 65: href: '/guides/employment-law/nsw-payroll-tax', 66: icon: DollarSign, 67: }, 68: { 69: slug: 'victoria-payroll-tax', 70: title: 'Victoria Payroll Tax', 71: description: '$3M threshold, 4.85% rate, regional rate (1.2125%), surcharges', 72: category: 'Payroll Tax', 73: state: 'VIC', 74: href: '/guides/employment-law/victoria-payroll-tax', 75: icon: DollarSign, 76: }, 77: ] 78: 79: // Filter out current page and limit items 80: const filteredPages = allEmploymentLawPages.filter((page) => page.slug !== currentSlug).slice(0, maxItems) 81: --- 82: 83:
84:
85: 86:
87: RELATED GUIDES 88:

Other employment law guides

89:

Explore other state-based guides for long service leave, workers' compensation, and payroll tax

90:
91: 92: 93:
94: { 95: filteredPages.map((page) => { 96: const Icon = page.icon 97: return ( 98: 99: {/* Icon Box */} 100:
101: 102:
103: 104: {/* Content */} 105:

{page.title}

106:

{page.description}

107: 108: {/* CTA */} 109:
110: Read guide 111: 112:
113:
114: ) 115: }) 116: } 117:
118:
119:
```` ## File: src/components/FAQSection.astro ````astro 1: --- 2: import { Plus, Minus } from 'lucide-astro' 3: 4: interface FAQ { 5: question: string 6: answer: string 7: } 8: 9: interface Category { 10: name: string 11: faqs: FAQ[] 12: } 13: 14: interface Props { 15: chip?: string 16: title?: string 17: description?: string 18: categories: Category[] 19: background?: 'primary' | 'white' 20: } 21: 22: const { chip = 'FAQ', title = 'Frequently asked questions', description, categories, background = 'primary' } = Astro.props 23: 24: const bgClass = background === 'white' ? 'bg-white' : 'bg-primary-100' 25: --- 26: 27:
28:
29:
30: {chip} 31:

{title}

32: {description &&

{description}

} 33:
34:
35: 36:
37:
38:
    39: { 40: categories.map((category, index) => ( 41:
  • 42: 52:
  • 53: )) 54: } 55:
56:
57: 58:
59: { 60: categories.map((category, catIndex) => ( 61:
    62: {(category.faqs || []).map((faq, faqIndex) => ( 63:
  • 64: 74:
    75:
    76:
    77:
  • 78: ))} 79:
80: )) 81: } 82:
83:
84:
85: 86: 133: 134: ```` ## File: src/components/FastFoodAwardCalculator.astro ````astro 1: --- 2: // Fast Food Award Rate Calculator Component 3: // Data from 2025 Fast Food Industry Award 2020 [MA000003] rates 4: 5: import { AlertTriangle, FileText, Clock, CheckCircle, ChevronDown, User, Calculator } from 'lucide-astro' 6: import TrialButton from './TrialButton.astro' 7: 8: const ratesData = { 9: permanent: { 10: 'Level 1': 26.55, 11: 'Level 2': 28.12, 12: 'Level 3': 28.9, 13: }, 14: casual: { 15: 'Level 1': 33.19, 16: 'Level 2': 35.15, 17: 'Level 3': 36.13, 18: }, 19: } 20: 21: // Fixed award rules - non-editable, shows how the Fast Food Award works 22: // Note: Sunday rates vary by classification level 23: const awardRules = [ 24: { 25: id: 'ordinary', 26: name: 'Ordinary hours (Mon-Fri, 7am-10pm)', 27: days: ['MON', 'TUE', 'WED', 'THU', 'FRI'], 28: startTime: '07:00', 29: endTime: '22:00', 30: penaltyMultiplier: { permanent: 1.0, casual: 1.0 }, 31: }, 32: { 33: id: 'evening', 34: name: 'Evening (Mon-Fri, 10pm-midnight)', 35: days: ['MON', 'TUE', 'WED', 'THU', 'FRI'], 36: startTime: '22:00', 37: endTime: '00:00', 38: penaltyMultiplier: { permanent: 1.1, casual: 1.35 }, 39: }, 40: { 41: id: 'latenight', 42: name: 'Late night (Mon-Fri, midnight-6am)', 43: days: ['MON', 'TUE', 'WED', 'THU', 'FRI'], 44: startTime: '00:00', 45: endTime: '06:00', 46: penaltyMultiplier: { permanent: 1.15, casual: 1.4 }, 47: }, 48: { 49: id: 'saturday', 50: name: 'Saturday (all day)', 51: days: ['SAT'], 52: startTime: '00:00', 53: endTime: '00:00', 54: penaltyMultiplier: { permanent: 1.25, casual: 1.5 }, 55: }, 56: { 57: id: 'sunday', 58: name: 'Sunday (varies by level)', 59: days: ['SUN'], 60: startTime: '00:00', 61: endTime: '00:00', 62: // Level 1: 125%/150%, Level 2/3: 150%/175% 63: penaltyMultiplier: { 64: 'Level 1': { permanent: 1.25, casual: 1.5 }, 65: 'Level 2': { permanent: 1.5, casual: 1.75 }, 66: 'Level 3': { permanent: 1.5, casual: 1.75 }, 67: }, 68: }, 69: { 70: id: 'publicholiday', 71: name: 'Public holiday', 72: days: ['HOL'], 73: startTime: '00:00', 74: endTime: '00:00', 75: penaltyMultiplier: { permanent: 2.25, casual: 2.5 }, 76: }, 77: ] 78: --- 79: 80:
81:
82:
AWARD RATE ESTIMATOR
83:

See how RosterElf interprets the Fast Food Award

84:

85: This is an educational example showing how the Fast Food Award penalty rates work. It demonstrates how RosterElf automatically calculates correct pay rates based on classification level, 86: employment type, and shift times. 87:

88:
89: 90: 91:
92:
93: 94:
95: Important: This is an estimator for demonstration purposes only. Do not use these calculations for actual payroll without verifying against the 96: official Fair Work pay guide 99: and consulting your Award obligations. 100:
101:
102:
103: 104: 105:
106:
107: 108:
109: 110:
111:
112: 113:
114: 121:
122:
123: 124: 125:
126: 127:
128:
129: 130:
131: 139:
140:
141:
142:
143: 144: 145:
146:
147:
148:
Base ordinary rate
149:
Mon-Fri, standard hours
150:
151:
152:
153: $ 154: 26.55 155: /hr 156:
157:
158:
159:
160: 161: 162:
163:

164: 165: Fast Food Award penalty rates 166:

167: 168:
169: 170:
171:
172: 173: 174:
175:

176: 177: Example weekly cost (38 hours) 178:

179: 180:
181: 182:
183: 184:
185: Example total: 186: $1,089.00 187:
188:
189: 190: 191:
192:
193:
194: 195:
196:

Example only - not for payroll use

197:

This is a demonstration of how RosterElf calculates award-compliant rates.

198:
199:
200: 210:
211: 212:
213:
214:
215:

The actual cost for your employees will depend on:

216: 217:
    218:
  • Their specific classification level and employment type
  • 219:
  • Actual hours worked and shift times
  • 220:
  • Any additional allowances, overtime, or enterprise agreement provisions
  • 221:
  • Current award rates (which change annually in July)
  • 222:
  • Junior rates if the employee is under 21
  • 223:
224: 225:

For accurate payroll calculations, always:

226: 227:
    228:
  1. 229: Verify current rates with the official Fair Work pay guide 235:
  2. 236:
  3. Confirm your employees' correct award coverage and classification
  4. 237:
  5. Use award interpretation software or consult a payroll professional
  6. 238:
  7. Review your specific enterprise agreement (if applicable)
  8. 239:
240: 241:

Do not rely on this example for actual wage payments.

242:
243:
244:
245:
246: 247: 248:
249: 250:
251:

Stop calculating penalty rates manually

252:

Let RosterElf handle award compliance automatically

253: 254:

255: Manual award calculations are time-consuming and error-prone. One mistake can lead to underpayments, compliance issues, and Fair Work penalties. RosterElf's award interpretation engine does 256: the work for you. 257:

258: 259:
260: 261:
262: 263:
264: 265: 266: No credit card required 267: 268: 269: 270: Full access 271: 272: 273: 274: 24/7 support 275: 276:
277:
278: 279: 280:
281:

How RosterElf automates award calculations

282: 283:
284: 285:
286:
287:
1
288: 289:
290:
Create pay templates
291:

292: Create pay templates for each classification level by adding award-compliant base rates and penalty multipliers. Once configured, RosterElf automatically applies the correct template to 293: each shift based on the employee's classification, shift timing, and employment type. 294:

295: Award interpretation → 296:
297: 298: 299:
300:
301:
2
302: 303:
304:
Define rate rules
305:

306: Configure when different penalty rates apply (late nights, weekends, public holidays). The system automatically detects which rate to use based on shift times and days. 307:

308: Penalty rates guide → 309:
310: 311: 312:
313:
314:
3
315: 316:
317:
Auto-apply to shifts
318:

319: Every rostered shift automatically calculates the correct pay rate based on the employee's classification, employment type, and shift timing. No manual work required. 320:

321: Payroll integration → 322:
323:
324: 325: 326:
327:

Learn more:

328: 335:
336:
337:
338:
339: 340: 583: 584: ```` ## File: src/components/FeatureAccordionTabs.astro ````astro 1: --- 2: import { ChevronDown, CalendarCog, Clock, Scale, Wallet, Users, MessageSquare, BarChart3 } from 'lucide-astro' 3: 4: interface AccordionItem { 5: title: string 6: description: string 7: link: string 8: linkText?: string 9: image: string 10: } 11: 12: interface Tab { 13: id: string 14: name: string 15: icon: typeof CalendarCog 16: items: AccordionItem[] 17: } 18: 19: interface Props { 20: background?: 'primary' | 'white' 21: chip?: string 22: title?: string 23: tabs?: Tab[] 24: sectionId?: string 25: } 26: 27: const { background = 'white', chip = 'All-in-one platform', title = 'One workforce platform — built for Australian teams', tabs: customTabs, sectionId = 'feature-accordion-section' } = Astro.props 28: // Light green background #f4faf6 for primary, white for white 29: const bgStyle = background === 'primary' ? 'background-color: #f4faf6;' : '' 30: const textClass = 'text-gray-900' 31: const chipClass = 'chip-primary' 32: const navBgClass = 'border-gray-200 bg-white' 33: 34: const defaultTabs: Tab[] = [ 35: { 36: id: 'rostering', 37: name: 'Rostering', 38: icon: CalendarCog, 39: items: [ 40: { 41: title: 'Create smart schedules in minutes', 42: description: 'Quickly create and share rosters from any device—save time and reduce last-minute chaos.', 43: link: '/features/rostering-software', 44: linkText: 'Explore rostering', 45: image: '/images/rostering-software-hero.webp', 46: }, 47: { 48: title: 'Control your labour costs', 49: description: 'See wage costs in real-time as you build rosters. Stay on budget before you publish.', 50: link: '/features/rostering-software#labour-budgeting', 51: linkText: 'Explore labour budgeting', 52: image: '/images/payroll-labour-budgets.webp', 53: }, 54: { 55: title: 'Fill shifts with the right people', 56: description: 'Perfect Match suggests available, qualified staff based on skills, availability and cost.', 57: link: '/features/rostering-software#auto-scheduling', 58: linkText: 'See Perfect Match', 59: image: '/images/auto-scheduling-hero.webp', 60: }, 61: { 62: title: 'Easy, fast, and staff-friendly', 63: description: 'Staff get instant notifications and can view rosters, swap shifts and update availability from the app.', 64: link: '/features/rostering-software', 65: linkText: 'Explore rostering', 66: image: '/images/auto-scheduling-open-shifts.webp', 67: }, 68: ], 69: }, 70: { 71: id: 'time-attendance', 72: name: 'Time & Attendance', 73: icon: Clock, 74: items: [ 75: { 76: title: 'GPS-verified clock-ins', 77: description: 'Know exactly when and where staff clock in with GPS location capture and photo verification.', 78: link: '/features/time-and-attendance', 79: linkText: 'View time tracking', 80: image: '/images/time-attendance-gps-verification.webp', 81: }, 82: { 83: title: 'Eliminate buddy punching', 84: description: 'Photo ID and GPS ensure the right person clocks in at the right location.', 85: link: '/features/time-and-attendance', 86: linkText: 'See verification', 87: image: '/images/time-attendance-photo-verification.webp', 88: }, 89: { 90: title: 'Real-time attendance tracking', 91: description: "See who's on shift, who's late, and who's missing—all from your dashboard.", 92: link: '/features/time-and-attendance', 93: linkText: 'View attendance', 94: image: '/images/time-attendance-live-dashboard.webp', 95: }, 96: { 97: title: 'Timesheet approvals made simple', 98: description: 'Review and approve timesheets with one click. Flag exceptions automatically.', 99: link: '/features/time-and-attendance', 100: linkText: 'Explore timesheets', 101: image: '/images/time-attendance-payroll-timesheets.webp', 102: }, 103: ], 104: }, 105: { 106: id: 'award-interpretation', 107: name: 'Award Interpretation', 108: icon: Scale, 109: items: [ 110: { 111: title: 'Automate penalty rates', 112: description: 'RosterElf calculates overtime, weekend rates and public holiday pay automatically.', 113: link: '/features/payroll-integration/award-interpretation', 114: linkText: 'View awards', 115: image: '/images/award-interpretation-penalty-rates.png', 116: }, 117: { 118: title: 'Stay Fair Work compliant', 119: description: 'Built-in award rules ensure you pay correctly every time—no manual calculations.', 120: link: '/features/payroll-integration/award-interpretation', 121: linkText: 'Explore compliance', 122: image: '/images/award-interpretation-fair-work.png', 123: }, 124: { 125: title: 'Support for 100+ awards', 126: description: "Hospitality, retail, healthcare, childcare and more—we've got your award covered.", 127: link: '/features/payroll-integration/award-interpretation', 128: linkText: 'See awards', 129: image: '/images/award-interpretation-100-awards.png', 130: }, 131: { 132: title: 'Reduce payroll disputes', 133: description: 'Accurate pay builds trust. Staff see exactly how their pay is calculated.', 134: link: '/features/payroll-integration/award-interpretation', 135: linkText: 'View benefits', 136: image: '/images/award-interpretation-reduce-disputes.png', 137: }, 138: ], 139: }, 140: { 141: id: 'payroll', 142: name: 'Payroll', 143: icon: Wallet, 144: items: [ 145: { 146: title: 'One-click Xero & MYOB export', 147: description: 'Send award-interpreted timesheets directly to your payroll software in seconds.', 148: link: '/features/payroll-integration', 149: linkText: 'See payroll', 150: image: '/images/payroll-integration-hero.webp', 151: }, 152: { 153: title: 'Payroll-ready timesheets', 154: description: 'Hours, rates and allowances calculated and formatted—ready for payroll.', 155: link: '/features/payroll-integration', 156: linkText: 'View payroll', 157: image: '/images/time-attendance-payroll-timesheets.webp', 158: }, 159: { 160: title: 'Eliminate manual data entry', 161: description: 'No more copying numbers between systems. Reduce errors and save hours.', 162: link: '/features/payroll-integration', 163: linkText: 'Explore integration', 164: image: '/images/payroll-no-data-entry.png', 165: }, 166: { 167: title: 'Full audit trail', 168: description: 'Track every change to timesheets with complete history for compliance.', 169: link: '/features/payroll-integration', 170: linkText: 'View audit trail', 171: image: '/images/payroll-audit-trail.png', 172: }, 173: ], 174: }, 175: { 176: id: 'hr', 177: name: 'HR Tools', 178: icon: Users, 179: items: [ 180: { 181: title: 'Digital onboarding & contracts', 182: description: 'Send contracts, policies and tax forms digitally so new starters complete everything before day one — no printing, chasing or filing.', 183: link: '/features/hr-software/employee-onboarding', 184: linkText: 'See onboarding', 185: image: '/images/hr-contracts.webp', 186: }, 187: { 188: title: 'Certifications, policies & procedures', 189: description: 'Track required documents, expiries and acknowledgements so nothing slips through the cracks — built for Australian workplaces.', 190: link: '/features/hr-software/policy-management', 191: linkText: 'View policies', 192: image: '/images/hr-certifications.webp', 193: }, 194: { 195: title: 'Leave & availability management', 196: description: 'Manage leave requests, balances and approvals in one system, synced with rosters to avoid clashes and short staffing.', 197: link: '/features/hr-software/leave-management-software', 198: linkText: 'Manage leave', 199: image: '/images/hr-leave-management.webp', 200: }, 201: { 202: title: 'Centralised employee records', 203: description: 'Store employee details, documents, certifications and history securely in one place, always up to date and easy to access.', 204: link: '/features/hr-software', 205: linkText: 'Explore HR tools', 206: image: '/images/hr-employee-records.png', 207: }, 208: ], 209: }, 210: { 211: id: 'communication', 212: name: 'Communication', 213: icon: MessageSquare, 214: items: [ 215: { 216: title: 'In-app team messaging', 217: description: 'Message individuals, teams or your whole workforce—all within RosterElf.', 218: link: '/features/communication', 219: linkText: 'View communication', 220: image: '/images/communication-hero.webp', 221: }, 222: { 223: title: 'Shift notifications', 224: description: 'Staff get instant alerts for new rosters, shift changes and open shifts.', 225: link: '/features/communication', 226: linkText: 'See notifications', 227: image: '/images/communication-shift-notifications.png', 228: }, 229: { 230: title: 'Announcements', 231: description: "Share important updates with read receipts so you know who's seen them.", 232: link: '/features/communication', 233: linkText: 'Explore messaging', 234: image: '/images/communication-team-chat.webp', 235: }, 236: { 237: title: 'Keep work chat separate', 238: description: 'No more WhatsApp groups. Keep work communication professional and private.', 239: link: '/features/communication', 240: linkText: 'View features', 241: image: '/images/communication-tasks.webp', 242: }, 243: ], 244: }, 245: { 246: id: 'analytics', 247: name: 'Analytics', 248: icon: BarChart3, 249: items: [ 250: { 251: title: 'Real-time labour insights', 252: description: 'See labour costs, hours worked and budget tracking at a glance.', 253: link: '/features/analytics', 254: linkText: 'See analytics', 255: image: '/images/roster-reporting-hero.webp', 256: }, 257: { 258: title: 'Attendance reports', 259: description: 'Track late arrivals, no-shows and overtime patterns across your team.', 260: link: '/features/analytics', 261: linkText: 'View reports', 262: image: '/images/time-attendance-live-dashboard.webp', 263: }, 264: { 265: title: 'Cost forecasting', 266: description: 'Predict wage costs before you publish rosters. Stay within budget.', 267: link: '/features/analytics', 268: linkText: 'Explore forecasting', 269: image: '/images/analytics-cost-forecasting.png', 270: }, 271: { 272: title: 'HR & compliance reports', 273: description: 'Download reports for payroll, compliance audits or management reviews.', 274: link: '/features/analytics', 275: linkText: 'View compliance', 276: image: '/images/hr-employee-records.png', 277: }, 278: ], 279: }, 280: ] 281: 282: // Use custom tabs if provided, otherwise use defaults 283: const tabs = customTabs || defaultTabs 284: --- 285: 286:
287:
288:
289: {chip} 290:

291: {title} 292:

293:
294: 295: 296:
297:
298: 324:
325:
326: 327: 328:
329: { 330: tabs.map((tab, tabIndex) => ( 331:
338:
339:
340: {tab.items.length === 1 ? ( 341: /* Single item - no accordion, just static content */ 342:
343:

{tab.items[0].title}

344:

345: 346: {tab.items[0].linkText || 'Learn more'} 347: 348:

349: ) : ( 350: /* Multiple items - full accordion */ 351: tab.items.map((item, itemIndex) => ( 352:
357: 361:
362:

{item.description}

363: 364: {item.linkText || 'Learn more'} 365: 366:
367:
368: )) 369: )} 370:
371: 372:
373: {tab.items.map((item, itemIndex) => ( 374: {`RosterElf 384: ))} 385:
386:
387:
388: )) 389: } 390:
391:
392:
393: 394: 516: 517: ```` ## File: src/components/FeatureCategoriesSection.astro ````astro 1: --- 2: import { Calendar, Clock, Landmark, Users, MessageCircle, BarChart3, ArrowRight, Check } from 'lucide-astro' 3: 4: // Interface for custom category data 5: export interface FeatureCategory { 6: name: string 7: tagline: string 8: description: string 9: icon: 'Calendar' | 'Clock' | 'Landmark' | 'Users' | 'MessageCircle' | 'BarChart3' 10: href: string 11: features: string[] 12: } 13: 14: interface Props { 15: chip?: string 16: title?: string 17: description?: string 18: background?: 'white' | 'primary' 19: categories?: FeatureCategory[] | null 20: } 21: 22: const { 23: chip = 'FEATURE CATEGORIES', 24: title = 'Everything you need to manage your workforce', 25: description = 'Six powerful modules working together to simplify rostering, time tracking, payroll, HR, communication, and analytics.', 26: background = 'white', 27: categories, 28: } = Astro.props 29: 30: // Icon map for string-based icon resolution 31: const iconMap = { 32: Calendar, 33: Clock, 34: Landmark, 35: Users, 36: MessageCircle, 37: BarChart3, 38: } 39: 40: const defaultCategories: FeatureCategory[] = [ 41: { 42: name: 'Employee rostering', 43: tagline: 'Build and manage rosters with ease', 44: description: 'Schedule the right staff, control labour costs, and stay compliant with AI-assisted rostering and live budget tracking.', 45: icon: 'Calendar', 46: href: '/features/rostering-software', 47: features: ['Auto-scheduling', 'Staff availability', 'Roster templates', 'Multi-site rosters', 'Break planning', 'Labour budgeting'], 48: }, 49: { 50: name: 'Time & attendance', 51: tagline: 'Track attendance with precision', 52: description: 'GPS clock-ins, photo proof, and digital timesheets ensure every clock-in is verified and accurate.', 53: icon: 'Clock', 54: href: '/features/time-and-attendance', 55: features: ['GPS & geofencing', 'Tablet time clock', 'Live attendance dashboard', 'Photo proof clock-in'], 56: }, 57: { 58: name: 'Payroll integration', 59: tagline: 'Export approved hours in one click', 60: description: 'Connect directly to Xero or MYOB. Automate award interpretation for overtime, penalties, and loadings.', 61: icon: 'Landmark', 62: href: '/features/payroll-integration', 63: features: ['Award interpretation', 'Xero integration', 'MYOB integration', 'Automated exports'], 64: }, 65: { 66: name: 'HR Hub', 67: tagline: 'Manage the full employee lifecycle', 68: description: 'From onboarding and digital contracts to policies, certificates, and leave management — all in one place.', 69: icon: 'Users', 70: href: '/features/hr-software', 71: features: ['Digital onboarding', 'Employment contracts', 'Certificate tracking', 'Workwise AI', 'Leave management'], 72: }, 73: { 74: name: 'Communication', 75: tagline: 'Keep everyone on the same page', 76: description: 'Built-in chat, shift messages, and announcements simplify team communication across all your locations.', 77: icon: 'MessageCircle', 78: href: '/features/communication', 79: features: ['Team chat app', 'Shift notes', 'Staff notifications', 'Shift swaps', 'Newsfeed'], 80: }, 81: { 82: name: 'Analytics', 83: tagline: 'Unlock instant visibility', 84: description: 'Real-time insights across rosters, wages, attendance, leave activity, HR compliance, and more.', 85: icon: 'BarChart3', 86: href: '/features/analytics', 87: features: ['Real-time roster insights', 'Labour cost reports', 'Attendance tracking', 'Compliance reporting'], 88: }, 89: ] 90: 91: // Use custom categories if provided, otherwise use defaults 92: const featureCategories = categories || defaultCategories 93: 94: const bgClass = background === 'primary' ? 'bg-primary-100' : 'bg-white' 95: --- 96: 97:
98:
99:
100: {chip} 101:

{title}

102:

{description}

103:
104: 105: 136:
137:
```` ## File: src/components/FeatureGuidesSection.astro ````astro 1: --- 2: import { ArrowRight, BookOpen } from 'lucide-astro' 3: import { getGuidesForFeature, type GuideInfo } from '../data/guideMappings' 4: 5: interface Props { 6: currentFeature: string 7: background?: 'white' | 'primary' 8: } 9: 10: const { currentFeature, background = 'primary' } = Astro.props 11: 12: const relatedGuides = getGuidesForFeature(currentFeature) 13: 14: const bgClass = background === 'white' ? 'bg-white' : 'bg-primary-100' 15: --- 16: 17: { 18: relatedGuides.length > 0 && ( 19:
20:
21:
22: HOW-TO GUIDES 23:

Learn how to get the most from this feature

24:

Step-by-step guides to help you master these workflows

25:
26: 27:
28: {relatedGuides.map((guide: GuideInfo) => ( 29: 33:
34: 35:
36:
37: {guide.name} 38: How-to guide 39:
40: 41:
42: ))} 43:
44: 45: 46: Browse all guides 47: 48: 49:
50:
51: ) 52: } ```` ## File: src/components/FeatureSection.astro ````astro 1: --- 2: interface Props { 3: chip: string 4: title: string 5: subChip: string 6: subtitle: string 7: paragraphs: string[] 8: ctaText?: string 9: ctaHref?: string 10: image: string 11: imageAlt: string 12: background?: 'white' | 'primary' 13: imagePosition?: 'left' | 'right' 14: } 15: 16: const { chip, title, subChip, subtitle, paragraphs, ctaText, ctaHref, image, imageAlt, background = 'white', imagePosition = 'left' } = Astro.props 17: 18: const bgClass = background === 'white' ? 'bg-white' : 'bg-primary-100' 19: const flexDirection = imagePosition === 'left' ? 'lg:flex-row' : 'lg:flex-row-reverse' 20: --- 21: 22:
23:
24:
25: {chip} 26:

{title}

27:
28: 29:
30: {imageAlt} 31: 32:
33: {subChip} 34:

{subtitle}

35: 36:
37: {paragraphs.map((p) =>

{p}

)} 38:
39: 40: { 41: ctaText && ctaHref && ( 42: 43: {ctaText} → 44: 45: ) 46: } 47:
48:
49:
50:
```` ## File: src/components/FeaturesGrid.astro ````astro 1: --- 2: import { ArrowRight } from 'lucide-astro' 3: import type { ComponentType } from 'astro/types' 4: 5: interface FeatureItem { 6: title: string 7: description: string 8: icon: ComponentType 9: href?: string 10: } 11: 12: interface Props { 13: chip?: string 14: title: string 15: description?: string 16: items: FeatureItem[] 17: columns?: 3 | 4 18: background?: 'white' | 'primary' 19: } 20: 21: const { chip = 'KEY FEATURES', title, description, items, columns = 4, background = 'white' } = Astro.props 22: 23: const bgClass = background === 'white' ? 'bg-white' : 'bg-primary-100' 24: const iconBgClass = background === 'white' ? 'bg-primary-100' : 'bg-white' 25: const gridCols = columns === 3 ? 'lg:grid-cols-3' : 'lg:grid-cols-4' 26: --- 27: 28:
29:
30:
31: {chip} 32:

{title}

33: {description &&

{description}

} 34:
35: 36:
37: { 38: items.map((item) => { 39: const IconComponent = item.icon 40: return item.href ? ( 41: 42:
43: 44:
45:

{item.title}

46:

{item.description}

47:
48: Explore {item.title.toLowerCase()} 49: 50:
51:
52: ) : ( 53:
54:
55: 56:
57:

{item.title}

58:

{item.description}

59:
60: ) 61: }) 62: } 63:
64:
65:
```` ## File: src/components/FeatureTabsSection.astro ````astro 1: --- 2: interface Props { 3: background?: 'primary' | 'white' 4: } 5: 6: const { background = 'primary' } = Astro.props 7: // Light green background #f4faf6 for primary 8: const bgStyle = background === 'primary' ? 'background-color: #f4faf6;' : '' 9: const textClass = 'text-gray-900' 10: const subtextClass = 'text-gray-600' 11: 12: interface FeatureTab { 13: id: string 14: name: string 15: tagline: string 16: image: string 17: link: string 18: } 19: 20: const tabs: FeatureTab[] = [ 21: { 22: id: 'rostering', 23: name: 'Rostering', 24: tagline: 'Roster the right people, at the right time, all across your business', 25: image: '/images/feature-tab-rostering.png', 26: link: '/features/rostering-software', 27: }, 28: { 29: id: 'time-attendance', 30: name: 'Time & Attendance', 31: tagline: 'Track every hour with GPS-verified clock-ins and real-time attendance', 32: image: '/images/feature-tab-time-attendance.png', 33: link: '/features/time-and-attendance', 34: }, 35: { 36: id: 'payroll', 37: name: 'Awards & Payroll', 38: tagline: 'Send accurate, award-compliant timesheets to Xero or MYOB in one click', 39: image: '/images/feature-tab-payroll.png', 40: link: '/features/payroll-integration', 41: }, 42: { 43: id: 'hr', 44: name: 'HR', 45: tagline: 'Manage onboarding, leave and compliance in one secure place', 46: image: '/images/feature-tab-hr.png', 47: link: '/features/hr-software', 48: }, 49: { 50: id: 'communication', 51: name: 'Communication', 52: tagline: 'Keep your team connected with secure workplace messaging', 53: image: '/images/feature-tab-communication.png', 54: link: '/features/communication', 55: }, 56: { 57: id: 'analytics', 58: name: 'Analytics', 59: tagline: 'Monitor labour costs and attendance trends in real time', 60: image: '/images/feature-tab-analytics.png', 61: link: '/features/analytics', 62: }, 63: ] 64: --- 65: 66:
67:
68:
69: All-in-one platform 70:

One workforce platform — built for Australian teams

71:
72: 73: 74:
75: 98:
99: 100: 101:
102: { 103: tabs.map((tab, index) => ( 104:
111:
112: {`RosterElf 113:
114: 115:
116:

{tab.tagline}

117: 118: Learn more 119: 120:
121:
122: )) 123: } 124:
125:
126:
127: 128: 223: 224: ```` ## File: src/components/FeatureTabsSimple.astro ````astro 1: --- 2: import { CalendarCog, Clock, Scale, Wallet, Users, BarChart3 } from 'lucide-astro' 3: 4: interface TabItem { 5: title: string 6: description: string 7: link: string 8: linkText?: string 9: image: string 10: } 11: 12: interface Tab { 13: id: string 14: name: string 15: icon: typeof CalendarCog 16: item: TabItem 17: } 18: 19: interface Props { 20: background?: 'primary' | 'white' 21: chip?: string 22: title?: string 23: tabs: Tab[] 24: sectionId?: string 25: } 26: 27: const { background = 'primary', chip = 'WHY ROSTERELF', title = 'Solve the hardest workforce problems — without adding admin', tabs, sectionId = 'feature-tabs-simple-section' } = Astro.props 28: 29: const bgStyle = background === 'primary' ? 'background-color: #f4faf6;' : '' 30: const textClass = 'text-gray-900' 31: const chipClass = 'chip-primary' 32: const navBgClass = 'border-gray-200 bg-white' 33: --- 34: 35:
36:
37:
38: {chip} 39:

40: {title} 41:

42:
43: 44: 45:
46:
47: 73:
74:
75: 76: 77:
78: { 79: tabs.map((tab, tabIndex) => ( 80:
87:
88:
89:

{tab.item.title}

90:

91: 92: {tab.item.linkText || 'Learn more'} 93: 94:

95: 96:
97: {`RosterElf 98:
99:
100:
101: )) 102: } 103:
104:
105:
106: 107: 167: 168: ```` ## File: src/components/FitnessAwardCalculator.astro ````astro 1: --- 2: // Fitness Award Rate Calculator Component 3: // Data from 2025 Fitness Industry Award rates 4: 5: import { AlertTriangle, FileText, Clock, CheckCircle, ChevronDown, User, Calculator } from 'lucide-astro' 6: import TrialButton from './TrialButton.astro' 7: 8: const ratesData = { 9: permanent: { 10: 'Level 1': 24.28, 11: 'Level 2': 24.95, 12: 'Level 3': 26.7, 13: 'Level 4': 29.27, 14: 'Level 5': 32.34, 15: 'Level 6': 32.06, 16: 'Level 7': 33.31, 17: }, 18: casual: { 19: 'Level 1': 30.35, // Mon-Fri: base × 1.25 20: 'Level 2': 31.19, 21: 'Level 3': 33.38, 22: 'Level 4': 36.59, 23: 'Level 5': 40.43, 24: 'Level 6': 40.08, 25: 'Level 7': 41.64, 26: }, 27: } 28: 29: // Fixed award rules - non-editable, shows how the award works 30: const awardRules = [ 31: { 32: id: 'ordinary-weekday', 33: name: 'Ordinary hours (Mon-Fri)', 34: days: ['MON', 'TUE', 'WED', 'THU', 'FRI'], 35: startTime: '05:00', 36: endTime: '21:00', 37: penaltyMultiplier: { permanent: 1.0, casual: 1.25 }, 38: }, 39: { 40: id: 'saturday', 41: name: 'Saturday', 42: days: ['SAT'], 43: penaltyMultiplier: { permanent: 1.25, casual: 1.3 }, 44: }, 45: { 46: id: 'sunday', 47: name: 'Sunday', 48: days: ['SUN'], 49: penaltyMultiplier: { permanent: 1.5, casual: 1.3 }, 50: }, 51: { 52: id: 'publicholiday', 53: name: 'Public holiday', 54: days: ['HOL'], 55: penaltyMultiplier: { permanent: 2.5, casual: 1.3 }, 56: }, 57: ] 58: --- 59: 60:
61:
62:
AWARD RATE ESTIMATOR
63:

See how RosterElf interprets the Fitness Award

64:

65: This is an educational example showing how the Fitness Award penalty rates work. It demonstrates how RosterElf automatically calculates correct pay rates based on classification level, 66: employment type, and shift times. 67:

68:
69: 70: 71:
72:
73: 74:
75: Important: This is an estimator for demonstration purposes only. Do not use these calculations for actual payroll without verifying against the 76: official Fair Work pay guide 79: and consulting your Award obligations. 80:
81:
82:
83: 84: 85:
86:
87: 88:
89: 90:
91:
92: 93:
94: 101:
102:
103: 104: 105:
106: 107:
108:
109: 110:
111: 123:
124:
125:
126:
127: 128: 129:
130:
131:
132:
Base ordinary rate
133:
Mon-Fri, standard hours
134:
135:
136:
137: $ 138: 24.28 139: /hr 140:
141:
142:
143:
144: 145: 146:
147:

148: 149: Fitness Award penalty rates 150:

151: 152:
153: 154:
155:
156: 157: 158:
159:

160: 161: Example weekly cost (38 hours) 162:

163: 164:
165: 166:
167: 168:
169: Example total: 170: $1,025.29 171:
172:
173: 174: 175:
176:
177:
178: 179:
180:

Example only - not for payroll use

181:

This is a demonstration of how RosterElf calculates award-compliant rates.

182:
183:
184: 194:
195: 196:
197:
198:
199:

The actual cost for your employees will depend on:

200: 201:
    202:
  • Their specific classification level and employment type
  • 203:
  • Actual hours worked and shift times
  • 204:
  • Any additional allowances, overtime, or enterprise agreement provisions
  • 205:
  • Current award rates (which change annually in July)
  • 206:
207: 208:

For accurate payroll calculations, always:

209: 210:
    211:
  1. 212: Verify current rates with the official Fair Work pay guide 218:
  2. 219:
  3. Confirm your employees' correct award coverage and classification
  4. 220:
  5. Use award interpretation software or consult a payroll professional
  6. 221:
  7. Review your specific enterprise agreement (if applicable)
  8. 222:
223: 224:

Do not rely on this example for actual wage payments.

225:
226:
227:
228:
229: 230: 231:
232: 233:
234:

Stop calculating penalty rates manually

235:

Let RosterElf handle award compliance automatically

236: 237:

238: Manual award calculations are time-consuming and error-prone. One mistake can lead to underpayments, compliance issues, and Fair Work penalties. RosterElf's award interpretation engine does 239: the work for you. 240:

241: 242:
243: 244:
245: 246:
247: 248: 249: No credit card required 250: 251: 252: 253: Full access 254: 255: 256: 257: 24/7 support 258: 259:
260:
261: 262: 263:
264:

How RosterElf automates award calculations

265: 266:
267: 268:
269:
270:
1
271: 272:
273:
Create pay templates
274:

275: Create pay templates for each classification level by adding award-compliant base rates and penalty multipliers. Once configured, RosterElf automatically applies the correct template to 276: each shift based on the employee's classification, shift timing, and employment type. 277:

278: Award interpretation → 279:
280: 281: 282:
283:
284:
2
285: 286:
287:
Define rate rules
288:

289: Configure when different penalty rates apply (weekends, public holidays). The system automatically detects which rate to use based on shift times and days. 290:

291: Penalty rates guide → 292:
293: 294: 295:
296:
297:
3
298: 299:
300:
Auto-apply to shifts
301:

302: Every rostered shift automatically calculates the correct pay rate based on the employee's classification, employment type, and shift timing. No manual work required. 303:

304: Payroll integration → 305:
306:
307: 308: 309:
310:

📚 Learn more:

311: 318:
319:
320:
321:
322: 323: 524: 525: ```` ## File: src/components/Footer.astro ````astro 1: --- 2: import { Facebook, Instagram, Twitter, Linkedin, Youtube, Star, ChevronDown } from 'lucide-astro' 3: import { ratingsData } from '../data/ratingsData' 4: import { footerLinks as footerLinksAU } from '../data/navigation-au' 5: import { footerLinks as footerLinksUK } from '../data/navigation-uk' 6: 7: interface Props { 8: country?: 'uk' | null 9: } 10: 11: const { country } = Astro.props 12: 13: // Select footer data based on country 14: const footerLinks = country === 'uk' ? footerLinksUK : footerLinksAU 15: const homeHref = country === 'uk' ? '/uk' : '/' 16: 17: // Icon mapping for social links 18: const socialIcons = { Facebook, Instagram, Twitter, Linkedin, Youtube } 19: 20: // NOTE: Hardcoded footerLinks removed - now using imported data from navigation-au.ts / navigation-uk.ts 21: --- 22: 23:
24: 25:
26:
27: 28:
29:
30: RosterElf logo 31:

{footerLinks.tagline}

32:
33: 34: 35:
36: { 37: footerLinks.appStores.map((store) => ( 38: 39: {store.alt} 40: 41: )) 42: } 43:
44: 45: 46:
47: { 48: footerLinks.social.map((social) => { 49: const iconName = social.name === 'X' ? 'Twitter' : social.name === 'LinkedIn' ? 'Linkedin' : social.name === 'YouTube' ? 'Youtube' : social.name 50: const IconComponent = socialIcons[iconName as keyof typeof socialIcons] 51: return ( 52: 59: {IconComponent && } 60: 61: ) 62: }) 63: } 64:
65:
66: 67: 68:
69: { 70: footerLinks.columns.map((column, index) => ( 71:
0 }]}> 72: 76: 85:
86: )) 87: } 88:
89:
90:
91: 92: 93:
94:
95:
96: 97:
{footerLinks.copyright}
98: 99: 100:
101: 127: 192:
193: 194: 195: 226:
227:
228:
229:
230: 271: 272: ```` ## File: src/components/FreeToolsGrid.astro ````astro 1: --- 2: /** 3: * FreeToolsGrid - App Store Style Tool Discovery Component 4: * 5: * A beautiful, reusable component to display free tools with filtering and cross-linking. 6: * Use on any page to help users discover related tools. 7: * 8: * Props: 9: * - title: Section title (default: "Explore more free tools") 10: * - subtitle: Section subtitle (optional) 11: * - background: "white" | "primary" (default: "primary") 12: * - excludeHref: Exclude a specific tool by its href (useful for current page) 13: * - category: Filter to specific category ("ai" | "rostering" | "cost" | "compliance" | "all") 14: * - maxTools: Maximum number of tools to display (default: all) 15: * - showFilters: Show category filter tabs (default: false) 16: * - layout: "grid" | "carousel" (default: "grid") 17: * - compact: Use smaller cards (default: false) 18: */ 19: 20: import { freeTools, toolCategories, getRelatedTools, type FreeTool } from '../data/freeToolsData' 21: import { ratingsData } from '../data/ratingsData' 22: import { 23: Calculator, 24: Calendar, 25: Bot, 26: ArrowRight, 27: Sparkles, 28: DollarSign, 29: Clock, 30: TrendingUp, 31: Percent, 32: Timer, 33: Coffee, 34: Shield, 35: AlertTriangle, 36: Briefcase, 37: FileSignature, 38: Star, 39: ChevronLeft, 40: ChevronRight, 41: } from 'lucide-astro' 42: 43: interface Props { 44: title?: string 45: subtitle?: string 46: background?: 'white' | 'primary' 47: excludeHref?: string // Optional - auto-detects current page if not provided 48: category?: 'ai' | 'rostering' | 'cost' | 'compliance' | 'all' 49: maxTools?: number 50: showFilters?: boolean 51: layout?: 'grid' | 'carousel' 52: compact?: boolean 53: prioritizeRelated?: boolean // Show same-category tools first (default: true) 54: } 55: 56: const { 57: title = 'Explore more free tools', 58: subtitle, 59: background = 'primary', 60: excludeHref, 61: category = 'all', 62: maxTools, 63: showFilters = false, 64: layout = 'grid', 65: compact = false, 66: prioritizeRelated = true, 67: } = Astro.props 68: 69: // Auto-detect current page if excludeHref not provided 70: const currentPath = excludeHref || Astro.url.pathname 71: 72: // Get the current tool to determine its category for related tools 73: const currentTool = freeTools.find((t) => t.href === currentPath) 74: 75: // Build filtered tools list 76: let filteredTools: FreeTool[] 77: 78: if (prioritizeRelated && currentTool && category === 'all') { 79: // Smart ordering: same category first, then other categories 80: const sameCategory = freeTools.filter((t) => t.category === currentTool.category && t.href !== currentPath) 81: const otherCategories = freeTools.filter((t) => t.category !== currentTool.category && t.href !== currentPath) 82: filteredTools = [...sameCategory, ...otherCategories] 83: } else { 84: // Standard filtering 85: filteredTools = freeTools.filter((t) => t.href !== currentPath) 86: 87: // Filter by category if specified 88: if (category !== 'all') { 89: filteredTools = filteredTools.filter((t) => t.category === category) 90: } 91: } 92: 93: // Limit number of tools 94: if (maxTools && maxTools > 0) { 95: filteredTools = filteredTools.slice(0, maxTools) 96: } 97: 98: // Generate unique ID for this instance (for carousel) 99: const instanceId = Math.random().toString(36).substring(7) 100: 101: // Icon mapping component 102: const iconMap: Record = { 103: Bot, 104: Calendar, 105: Calculator, 106: DollarSign, 107: Clock, 108: TrendingUp, 109: Percent, 110: Timer, 111: Coffee, 112: Shield, 113: AlertTriangle, 114: Briefcase, 115: FileSignature, 116: Sparkles, 117: } 118: --- 119: 120:
121:
122: 123:
124:

{title}

125: {subtitle &&

{subtitle}

} 126:
127: 128: 129: { 130: showFilters && ( 131:
132: {toolCategories.map((cat) => ( 133: 150: ))} 151:
152: ) 153: } 154: 155: 156: { 157: layout === 'grid' && ( 158:
159: {filteredTools.map((tool) => { 160: const IconComponent = iconMap[tool.icon] 161: return ( 162: 170: {/* Gradient accent on hover */} 171: 216: ) 217: } 218: 219: 220: { 221: layout === 'carousel' && ( 222:
223: {/* Carousel Container */} 224:
225: 275: 276: {/* Navigation Arrows */} 277: 285: 293: 294: {/* Dots indicator */} 295:
296: {Array.from({ length: Math.ceil(filteredTools.length / 3) }).map((_, i) => ( 297:
305:
306: ) 307: } 308: 309: 310: 322:
323:
324: 325: 405: 406: ```` ## File: src/components/FreeVsPaidComparison.astro ````astro 1: --- 2: /** 3: * FreeVsPaidComparison Component 4: * 5: * Side-by-side comparison of Free Tools vs RosterElf Full Suite 6: * Uses dynamic pricing from pricingData.ts 7: * Supports custom content for specific tool pages 8: */ 9: 10: import { Check, X, ArrowRight, Star } from 'lucide-astro' 11: import TrialButton from './TrialButton.astro' 12: import { pricingRates, plans, annualDiscountPercent, freeTrialDays } from '../data/pricingData' 13: 14: interface FeatureItem { 15: text: string 16: included: boolean 17: } 18: 19: interface Props { 20: background?: 'white' | 'primary' 21: /** Custom heading - defaults to "Need more than free tools?" */ 22: title?: string 23: /** Custom subtitle */ 24: subtitle?: string 25: /** Title for the free tools card */ 26: freeTitle?: string 27: /** Description under the free tools price */ 28: freeDescription?: string 29: /** Custom features for the free side */ 30: freeFeatures?: FeatureItem[] 31: /** Link for "Continue with Free" button */ 32: continueLink?: string 33: /** Text for continue button */ 34: continueText?: string 35: } 36: 37: const { 38: background = 'white', 39: title = 'Need more than free tools?', 40: subtitle = 'Upgrade to RosterElf for automated scheduling, award compliance, and payroll integration.', 41: freeTitle = 'Free Tools', 42: freeDescription = 'Perfect for quick calculations and one-off tasks', 43: freeFeatures: customFreeFeatures, 44: continueLink = '#tools-section', 45: continueText = 'Continue with Free', 46: } = Astro.props 47: 48: const bgClass = background === 'white' ? 'bg-white' : 'bg-primary-100' 49: 50: // Get Full Suite plan details 51: const fullSuitePlan = plans.find((p) => p.id === 'fullSuite')! 52: const annualPrice = pricingRates.fullSuite.annual 53: const monthlyPrice = pricingRates.fullSuite.monthly 54: 55: // Default free features if not provided 56: const defaultFreeFeatures: FeatureItem[] = [ 57: { text: '14 free tools', included: true }, 58: { text: 'No signup required', included: true }, 59: { text: 'Instant browser access', included: true }, 60: { text: 'Basic calculators & estimators', included: true }, 61: { text: 'Save & sync rosters', included: false }, 62: { text: 'Award interpretation', included: false }, 63: { text: 'Payroll integration', included: false }, 64: { text: 'Team management', included: false }, 65: ] 66: 67: const freeFeatures = customFreeFeatures || defaultFreeFeatures 68: 69: // Core features that Full Suite includes 70: const coreFeatures = ['Smart rostering & availability', 'Time & attendance (GPS & photo)', 'Award interpretation & penalties', 'Payroll export (Xero & MYOB)'] 71: 72: // Combine core + Full Suite specific features 73: const proFeatures = [...coreFeatures.map((f) => ({ text: f, included: true })), ...fullSuitePlan.features.map((f) => ({ text: f, included: true }))] 74: --- 75: 76:
77:
78:
79:

{title}

80:

81: {subtitle} 82:

83:
84: 85:
86: 87:
88:
89:

{freeTitle}

90:
91: $0 92: forever 93:
94:

{freeDescription}

95:
96: 97:
    98: { 99: freeFeatures.map((feature) => ( 100:
  • 101: {feature.included ? : } 102: {feature.text} 103:
  • 104: )) 105: } 106:
107: 108: 112: {continueText} 113: 114:
115: 116: 117:
118: 119:
120: 121: MOST POPULAR 122:
123: 124:
125:

{fullSuitePlan.name}

126:

{fullSuitePlan.tagline}

127: 128: 129:
130:
131: 132: ${annualPrice.toFixed(2)} 133: 134: AUD 135:
136:

137: per employee per month
138: + GST, billed annually 139:

140:
141: 142: 143:
144:
145: 146: 147:
148: 149: Save {annualDiscountPercent}% 150: 151:
152: 153:

{fullSuitePlan.description}

154:
155: 156:
    157: { 158: proFeatures.map((feature) => ( 159:
  • 160: 161: {feature.text} 162:
  • 163: )) 164: } 165:
166: 167: 168: 169:

No credit card required · {freeTrialDays}-day free trial

170:
171:
172: 173: 174: 184:
185:
186: 187: ```` ## File: src/components/GeneralRetailAwardCalculator.astro ````astro 1: --- 2: // General Retail Award Rate Calculator Component 3: // Data from 2025/26 General Retail Industry Award rates 4: 5: import { AlertTriangle, FileText, Clock, CheckCircle, ChevronDown, User, Calculator } from 'lucide-astro' 6: import TrialButton from './TrialButton.astro' 7: 8: const ratesData = { 9: permanent: { 10: 'Level 1': 26.55, 11: 'Level 2': 27.6, 12: 'Level 3': 28.55, 13: 'Level 4': 29.61, 14: 'Level 5': 30.69, 15: 'Level 6': 32.06, 16: 'Level 7': 33.42, 17: 'Level 8': 35.64, 18: }, 19: casual: { 20: 'Level 1': 33.19, 21: 'Level 2': 34.5, 22: 'Level 3': 35.69, 23: 'Level 4': 37.01, 24: 'Level 5': 38.36, 25: 'Level 6': 40.08, 26: 'Level 7': 41.78, 27: 'Level 8': 44.55, 28: }, 29: } 30: 31: // Fixed award rules - non-editable, shows how the award works 32: const awardRules = [ 33: { 34: id: 'ordinary', 35: name: 'Ordinary hours (Mon-Fri before 6pm)', 36: days: ['MON', 'TUE', 'WED', 'THU', 'FRI'], 37: startTime: '00:00', 38: endTime: '18:00', 39: penaltyMultiplier: { permanent: 1.0, casual: 1.25 }, 40: }, 41: { 42: id: 'evening', 43: name: 'Evening (Mon-Fri after 6pm)', 44: days: ['MON', 'TUE', 'WED', 'THU', 'FRI'], 45: startTime: '18:00', 46: endTime: '00:00', 47: penaltyMultiplier: { permanent: 1.25, casual: 1.5 }, 48: }, 49: { 50: id: 'saturday-before', 51: name: 'Saturday before 6pm', 52: days: ['SAT'], 53: startTime: '00:00', 54: endTime: '18:00', 55: penaltyMultiplier: { permanent: 1.25, casual: 1.5 }, 56: }, 57: { 58: id: 'saturday-after', 59: name: 'Saturday after 6pm', 60: days: ['SAT'], 61: startTime: '18:00', 62: endTime: '00:00', 63: penaltyMultiplier: { permanent: 1.5, casual: 1.75 }, 64: }, 65: { 66: id: 'sunday', 67: name: 'Sunday (all day)', 68: days: ['SUN'], 69: startTime: '00:00', 70: endTime: '00:00', 71: penaltyMultiplier: { permanent: 1.5, casual: 1.75 }, 72: }, 73: { 74: id: 'publicholiday', 75: name: 'Public holiday', 76: days: ['HOL'], 77: startTime: '00:00', 78: endTime: '00:00', 79: penaltyMultiplier: { permanent: 2.25, casual: 2.5 }, 80: }, 81: ] 82: --- 83: 84:
85:
86:
AWARD RATE ESTIMATOR
87:

See how RosterElf interprets the General Retail Award

88:

89: This is an educational example showing how the General Retail Award penalty rates work. It demonstrates how RosterElf automatically calculates correct pay rates based on classification level, 90: employment type, and shift times. 91:

92:
93: 94: 95:
96:
97: 98:
99: Important: This is an estimator for demonstration purposes only. Do not use these calculations for actual payroll without verifying against the 100: official Fair Work pay guide 103: and consulting your Award obligations. 104:
105:
106:
107: 108: 109:
110:
111: 112:
113: 114:
115:
116: 117:
118: 125:
126:
127: 128: 129:
130: 131:
132:
133: 134:
135: 148:
149:
150:
151:
152: 153: 154:
155:
156:
157:
Base ordinary rate
158:
Mon-Fri, before 6pm
159:
160:
161:
162: $ 163: 26.55 164: /hr 165:
166:
167:
168:
169: 170: 171:
172:

173: 174: General Retail Award penalty rates 175:

176: 177:
178: 179:
180:
181: 182: 183:
184:

185: 186: Example weekly cost (38 hours) 187:

188: 189:
190: 191:
192: 193:
194: Example total: 195: $1,089.90 196:
197:
198: 199: 200:
201:
202:
203: 204:
205:

Example only - not for payroll use

206:

This is a demonstration of how RosterElf calculates award-compliant rates.

207:
208:
209: 219:
220: 221:
222:
223:
224:

The actual cost for your employees will depend on:

225: 226:
    227:
  • Their specific classification level and employment type
  • 228:
  • Actual hours worked and shift times
  • 229:
  • Any additional allowances, overtime, or enterprise agreement provisions
  • 230:
  • Current award rates (which change annually in July)
  • 231:
232: 233:

For accurate payroll calculations, always:

234: 235:
    236:
  1. 237: Verify current rates with the official Fair Work pay guide 243:
  2. 244:
  3. Confirm your employees' correct award coverage and classification
  4. 245:
  5. Use award interpretation software or consult a payroll professional
  6. 246:
  7. Review your specific enterprise agreement (if applicable)
  8. 247:
248: 249:

Do not rely on this example for actual wage payments.

250:
251:
252:
253:
254: 255: 256:
257: 258:
259:

Stop calculating penalty rates manually

260:

Let RosterElf handle award compliance automatically

261: 262:

263: Manual award calculations are time-consuming and error-prone. One mistake can lead to underpayments, compliance issues, and Fair Work penalties. RosterElf's award interpretation engine does 264: the work for you. 265:

266: 267:
268: 269:
270: 271:
272: 273: 274: No credit card required 275: 276: 277: 278: Full access 279: 280: 281: 282: 24/7 support 283: 284:
285:
286: 287: 288:
289:

How RosterElf automates award calculations

290: 291:
292: 293:
294:
295:
1
296: 297:
298:
Create pay templates
299:

300: Create pay templates for each classification level by adding award-compliant base rates and penalty multipliers. Once configured, RosterElf automatically applies the correct template to 301: each shift based on the employee's classification, shift timing, and employment type. 302:

303: Award interpretation → 304:
305: 306: 307:
308:
309:
2
310: 311:
312:
Define rate rules
313:

314: Configure when different penalty rates apply (evenings, weekends, public holidays). The system automatically detects which rate to use based on shift times and days. 315:

316: Penalty rates guide → 317:
318: 319: 320:
321:
322:
3
323: 324:
325:
Auto-apply to shifts
326:

327: Every rostered shift automatically calculates the correct pay rate based on the employee's classification, employment type, and shift timing. No manual work required. 328:

329: Payroll integration → 330:
331:
332: 333: 334:
335:

Learn more:

336: 343:
344:
345:
346:
347: 348: 573: 574: ```` ## File: src/components/GeoLocationModal.astro ````astro 1: --- 2: // Geo-Location Modal - prompts UK visitors to choose between AU and UK sites 3: --- 4: 5: 46: 47: ```` ## File: src/components/GlossaryRelatedResources.astro ````astro 1: --- 2: import { ChevronRight } from 'lucide-astro' 3: import { readFile } from 'node:fs/promises' 4: import { join } from 'node:path' 5: 6: interface Article { 7: title: string 8: href: string 9: } 10: 11: interface Term { 12: term: string 13: slug?: string 14: } 15: 16: interface Props { 17: articles?: Article[] 18: terms?: Term[] 19: } 20: 21: /** 22: * Check if a blog post has a future premiere date 23: */ 24: async function hasFuturePremiereDate(blogSlug: string): Promise { 25: try { 26: const filePath = join(process.cwd(), 'src/pages/blog', `${blogSlug}.astro`) 27: const content = await readFile(filePath, 'utf-8') 28: 29: // Extract premiere date from content 30: const premiereDateMatch = content.match(/premiereDate\s*=\s*['"]([^'"]+)['"]/) 31: if (!premiereDateMatch) return false 32: 33: const premiereDate = new Date(premiereDateMatch[1]) 34: const now = new Date() 35: 36: // Compare dates at midnight 37: now.setHours(0, 0, 0, 0) 38: premiereDate.setHours(0, 0, 0, 0) 39: 40: return premiereDate > now 41: } catch { 42: // If file doesn't exist or can't be read, assume it's not a blog post or is published 43: return false 44: } 45: } 46: 47: /** 48: * Filter out articles with future premiere dates (blog posts only) 49: */ 50: async function filterPublishedArticles(articles: Article[]): Promise { 51: const results = await Promise.all( 52: articles.map(async (article) => { 53: // Only check blog posts (href starts with /blog/) 54: if (!article.href.startsWith('/blog/')) return { article, isPublished: true } 55: 56: // Extract slug from href 57: const slug = article.href.replace('/blog/', '') 58: const isFuture = await hasFuturePremiereDate(slug) 59: 60: return { article, isPublished: !isFuture } 61: }) 62: ) 63: 64: return results.filter((r) => r.isPublished).map((r) => r.article) 65: } 66: 67: const { articles = [], terms = [] } = Astro.props 68: 69: // Filter out unpublished blog posts 70: const publishedArticles = await filterPublishedArticles(articles) 71: 72: const hasArticles = publishedArticles.length > 0 73: const hasTerms = terms.length > 0 74: const hasContent = hasArticles || hasTerms 75: --- 76: 77: { 78: hasContent && ( 79:
80:
81:

Related resources

82:

Explore more guides and definitions

83: 84:
85: {/* Articles */} 86: {publishedArticles.map((article) => ( 87: 91: {article.title} 92: 93: 94: ))} 95: 96: {/* Terms */} 97: {terms.map((item) => 98: item.slug ? ( 99: 103: {item.term} 104: 105: 106: ) : ( 107:
108: {item.term} 109: Coming soon 110:
111: ) 112: )} 113:
114:
115:
116: ) 117: } 118: 119: ```` ## File: src/components/GlossarySupportLinks.astro ````astro 1: --- 2: import { ChevronRight, BookOpen } from 'lucide-astro' 3: 4: interface SupportArticleLink { 5: title: string 6: href: string 7: description?: string 8: type?: 'setup' | 'integration' | 'advanced' 9: } 10: 11: interface Props { 12: articles: SupportArticleLink[] 13: maxLinks?: number 14: } 15: 16: const { articles = [], maxLinks = 4 } = Astro.props 17: 18: // Limit to maxLinks 19: const displayArticles = articles.slice(0, maxLinks) 20: 21: const hasArticles = displayArticles.length > 0 22: --- 23: 24: { 25: hasArticles && ( 26:
27:
28:
29:
30: 31:
32:
33:

How to implement in RosterElf

34:

Step-by-step guides to set this up

35:
36:
37: 38: 55: 56: {articles.length > maxLinks &&

+{articles.length - maxLinks} more implementation guides

} 57:
58:
59: ) 60: } ```` ## File: src/components/Header.astro ````astro 1: --- 2: import { 3: ChevronDown, 4: Grid3x3, 5: Calendar, 6: Clock, 7: DollarSign, 8: Users, 9: MessageCircle, 10: Headphones, 11: BarChart, 12: CalendarCheck, 13: CalendarClock, 14: Smartphone, 15: ClipboardList, 16: UserCheck, 17: CalendarDays, 18: Building2, 19: AlertTriangle, 20: FileStack, 21: ListTodo, 22: Tablet, 23: MapPin, 24: Camera, 25: Award, 26: Heart, 27: Star, 28: Quote, 29: FileText, 30: GitCompare, 31: Puzzle, 32: Tag, 33: HelpCircle, 34: Sparkles, 35: Video, 36: BookOpen, 37: Phone, 38: Mail, 39: ThumbsUp, 40: Info, 41: FileUser, 42: UserPlus, 43: FileSignature, 44: ShieldCheck, 45: FolderOpen, 46: Briefcase, 47: LogOut, 48: GraduationCap, 49: TrendingUp, 50: Smile, 51: Bot, 52: Bell, 53: StickyNote, 54: Rss, 55: Activity, 56: Landmark, 57: ChartArea, 58: LayoutTemplate, 59: ChevronRight, 60: ArrowRight, 61: ChartColumnDecreasing, 62: Coffee, 63: ArrowLeftRight, 64: Hand, 65: Megaphone, 66: Calculator, 67: ClipboardCheck, 68: MessageSquare, 69: Newspaper, 70: CalendarMinus, 71: LogIn, 72: } from 'lucide-astro' 73: import TrialButton from './TrialButton.astro' 74: import { headerNavigation as navigationAU } from '../data/navigation-au' 75: import { headerNavigation as navigationUK } from '../data/navigation-uk' 76: 77: interface Props { 78: country?: 'uk' | null 79: } 80: 81: const { country } = Astro.props 82: 83: // Select navigation data based on country 84: const navigation = country === 'uk' ? navigationUK : navigationAU 85: const homeHref = country === 'uk' ? '/uk' : '/' 86: const pricingHref = country === 'uk' ? '/uk/pricing' : '/pricing' 87: 88: // Icon mapping helper 89: const iconMap = { 90: Grid3x3, 91: Calendar, 92: Clock, 93: DollarSign, 94: Users, 95: MessageCircle, 96: Headphones, 97: BarChart, 98: CalendarCheck, 99: CalendarClock, 100: Smartphone, 101: ClipboardList, 102: UserCheck, 103: CalendarDays, 104: Building2, 105: AlertTriangle, 106: FileStack, 107: ListTodo, 108: Tablet, 109: MapPin, 110: Camera, 111: Award, 112: Heart, 113: Star, 114: Quote, 115: FileText, 116: GitCompare, 117: Puzzle, 118: Tag, 119: HelpCircle, 120: Sparkles, 121: Video, 122: BookOpen, 123: Phone, 124: Mail, 125: ThumbsUp, 126: Info, 127: FileUser, 128: UserPlus, 129: FileSignature, 130: ShieldCheck, 131: FolderOpen, 132: Briefcase, 133: LogOut, 134: GraduationCap, 135: TrendingUp, 136: Smile, 137: Bot, 138: Bell, 139: StickyNote, 140: Rss, 141: Activity, 142: Landmark, 143: ChartArea, 144: LayoutTemplate, 145: ChartColumnDecreasing, 146: Coffee, 147: ArrowLeftRight, 148: Hand, 149: Megaphone, 150: Calculator, 151: ClipboardCheck, 152: MessageSquare, 153: Newspaper, 154: CalendarMinus, 155: LogIn, 156: } 157: 158: // Helper to render icon (Lucide or image) 159: const renderIcon = (icon: string, size: number, isImage?: boolean) => { 160: if (isImage) { 161: return { type: 'image', src: icon, size } 162: } 163: const Icon = iconMap[icon as keyof typeof iconMap] 164: return { type: 'icon', component: Icon, size } 165: } 166: 167: // Menu item type 168: type MenuItem = { 169: type: 'complex' | 'simple' | 'link' 170: label: string 171: icon?: string 172: href?: string 173: sections?: any[] 174: links?: any[] 175: class?: string 176: } 177: 178: // NOTE: Navigation data is now imported from src/data/navigation-au.ts or navigation-uk.ts 179: // The 'navigation' variable is set at the top of the frontmatter based on 'country' prop 180: 181: // Navigation data imported from data files (see imports above) 182: 183: // Filter out MYOB for UK 184: if (country === 'uk') { 185: // Remove MYOB from Payroll Integration section links 186: const payrollSection = navigation.product.sections.find((s) => s.id === 'payroll-integration') 187: if (payrollSection) { 188: payrollSection.links = payrollSection.links.filter((l: any) => l.label !== 'MYOB Integration') 189: payrollSection.highlight.description = 'Automate payroll by linking rosters with Xero.' 190: } 191: // Update Integrations menu: remove MYOB, point Google Maps to UK version 192: const integrationsMenu = navigation.simpleMenus[1] 193: if (integrationsMenu) { 194: integrationsMenu.links = integrationsMenu.links.filter((l) => l.label !== 'MYOB') 195: const googleMapsLink = integrationsMenu.links.find((l) => l.label === 'Google Maps') 196: if (googleMapsLink) { 197: googleMapsLink.href = '/uk/integrations/google-maps' 198: } 199: const googleCalendarLink = integrationsMenu.links.find((l) => l.label === 'Google Calendar') 200: if (googleCalendarLink) { 201: googleCalendarLink.href = '/uk/integrations/google-calendar' 202: } 203: const chatGptLink = integrationsMenu.links.find((l) => l.label === 'ChatGPT Atlas') 204: if (chatGptLink) { 205: chatGptLink.href = '/uk/integrations/chat-gpt' 206: } 207: } 208: } 209: 210: // Combined menu structure in order: Product, Why Us, Integrations, Pricing, Support, Resources 211: const nav2 = navigation.simpleMenus[2] as any 212: const nav2Type: 'link' | 'simple' = nav2?.href && !nav2?.links && !nav2?.columns ? 'link' : 'simple' 213: const menuItems: MenuItem[] = [ 214: { type: 'complex', ...navigation.product }, 215: { type: 'simple', ...navigation.simpleMenus[0] }, // Why Us 216: { type: 'simple', ...navigation.simpleMenus[1] }, // Integrations 217: { type: 'link', label: 'Pricing', icon: 'Tag', href: pricingHref }, 218: { type: 'simple', ...navigation.simpleMenus[3] }, // Support 219: { type: nav2Type, ...navigation.simpleMenus[2] } as MenuItem, // Resources or Blog 220: { type: 'link', label: 'Login', icon: 'LogIn', href: 'https://rosterelf.net/', class: 'lg:hidden' }, 221: ] 222: 223: // Standard icon sizes 224: const ICON_SIZE = 24 225: const CHEVRON_SIZE = 16 226: --- 227: 228:
229:
230: 231: RosterElf Logo 232: {country === 'uk' && UK} 233: 234: 465:
466: 474: 475: 476: 477: 489:
490:
491:
492: 493: 668: 669: ```` ## File: src/components/HeroAiTool.astro ````astro 1: --- 2: import { Check, ExternalLink, Bookmark, Sparkles } from 'lucide-astro' 3: 4: interface Feature { 5: text: string 6: } 7: 8: interface ChatMessage { 9: type: 'user' | 'ai' 10: text: string 11: template?: string 12: } 13: 14: interface Props { 15: chip?: string 16: title: string 17: subtitle: string 18: features: Feature[] 19: chatHeader: string 20: chatMessages?: ChatMessage[] 21: ctaText: string 22: ctaSubtext?: string 23: showBookmark?: boolean 24: } 25: 26: const { chip = 'FREE AI TOOL', title, subtitle, features, chatHeader, chatMessages, ctaText, ctaSubtext = 'Opens in ChatGPT (free account required)', showBookmark = true } = Astro.props 27: 28: const hasCustomChat = Astro.slots.has('chat') 29: --- 30: 31:
32:
33:
34: 35:
36: {chip} 37:

38:

{subtitle}

39:
40: { 41: features.map((feature) => ( 42:
43: 44: {feature.text} 45:
46: )) 47: } 48:
49:

50: 51:
52:
53: 54:
55:
56: 57:
58:

{chatHeader}

59:
60: 61:
62: { 63: hasCustomChat ? ( 64: 65: ) : ( 66: chatMessages?.map((message) => 67: message.type === 'user' ? ( 68:
69:
70:

{message.text}

71:
72:
73: ) : ( 74:
75:
76:

{message.text}

77: {message.template &&

{message.template}

} 78:
79:
80: ) 81: ) 82: ) 83: } 84:
85:
86:
87:
88:
89: 90:
91:
92:
93: { 94: showBookmark && ( 95: 99: ) 100: } 101:
102:
103: 110:

{ctaSubtext}

111:
112:
113:
114:
```` ## File: src/components/HeroLite.astro ````astro 1: --- 2: /** 3: * HeroLite - Lightweight hero section for landing pages 4: * 5: * Usage: 6: * 7: * 8: * Custom headline here 9: * 10: */ 11: import TrialButton from './TrialButton.astro' 12: 13: interface Props { 14: element: string 15: chip: string 16: description: string 17: } 18: 19: const { element, chip = '', description = '' } = Astro.props 20: --- 21: 22:
23:
24: {chip} 25:

26: 27:

28:

{description}

29: 30: 31: 42: 43:

15-day free trial. No credit card required.

44:
45:
```` ## File: src/components/HeroSection.astro ````astro 1: --- 2: import Breadcrumb from './Breadcrumb.astro' 3: import { Star, Check, CreditCard } from 'lucide-astro' 4: import TrialButton from './TrialButton.astro' 5: 6: interface BreadcrumbItem { 7: label: string 8: href: string 9: } 10: 11: interface BulletPoint { 12: text: string 13: } 14: 15: interface CTA { 16: text: string 17: href: string 18: variant: 'primary' | 'secondary' 19: target?: '_blank' 20: } 21: 22: interface Props { 23: breadcrumbs?: BreadcrumbItem[] 24: chip?: string 25: title: string 26: description?: string 27: bulletPoints?: BulletPoint[] 28: ctas?: CTA[] 29: showRating?: boolean 30: heroImage: string 31: heroImageAlt: string 32: showNoCreditCard?: boolean 33: hideBreadcrumbSpace?: boolean 34: } 35: 36: const { breadcrumbs, chip, title, description, bulletPoints, ctas, showRating = false, heroImage, heroImageAlt, showNoCreditCard = true, hideBreadcrumbSpace = false } = Astro.props 37: --- 38: 39:
40:
41: 42: { 43: breadcrumbs && breadcrumbs.length > 0 && ( 44:
45: 46:
47: ) 48: } 49: {!breadcrumbs && !hideBreadcrumbSpace &&
} 50: {!breadcrumbs && hideBreadcrumbSpace &&
} 51: 52: 53:
54: 55:
56: {chip && {chip}} 57: 58:

59: 60: 61:
62: {heroImageAlt} 63:
64: 65: {description &&

{description}

} 66: 67: { 68: bulletPoints && bulletPoints.length > 0 && ( 69:
    70: {bulletPoints.map((point) => ( 71:
  • 72:
    73: 74:
    75:

    {point.text}

    76:
  • 77: ))} 78:
79: ) 80: } 81: 82:
83:
84: 85: { 86: ctas && 87: ctas.map((cta) => ( 88: 96: {cta.text} 97: 98: )) 99: } 100:
101: { 102: showNoCreditCard && ( 103:
104: 105: No credit card required 106:
107: ) 108: } 109:
110: 111: 112: { 113: showRating && ( 114:
115:
116:
117: {Array.from({ length: 5 }).map(() => ( 118: 119: ))} 120:
121: 4.8 stars, 1,570 ratings 122:
123:

124: Best-rated rostering & HR software on{' '} 125: 126: Xero 127: {' '} 128: and{' '} 129: 135: Google 136: 137:

138:
139: ) 140: } 141:
142:

143: 144: 145: 148:
149:
150:
```` ## File: src/components/HospitalityAwardCalculator.astro ````astro 1: --- 2: // Hospitality Award Rate Calculator Component 3: // Data from 2025 Hospitality Industry (General) Award rates 4: 5: import { AlertTriangle, FileText, Clock, CheckCircle, ChevronDown, User, Calculator } from 'lucide-astro' 6: import TrialButton from './TrialButton.astro' 7: 8: const ratesData = { 9: permanent: { 10: Introductory: 24.28, 11: 'Level 1': 24.95, 12: 'Level 2': 25.85, 13: 'Level 3': 26.7, 14: 'Level 4': 28.12, 15: 'Level 5': 29.88, 16: 'Level 6': 30.68, 17: 'Managerial staff – hotel': 30.73, 18: }, 19: casual: { 20: Introductory: 30.35, 21: 'Level 1': 31.19, 22: 'Level 2': 32.31, 23: 'Level 3': 33.38, 24: 'Level 4': 35.15, 25: 'Level 5': 37.35, 26: 'Level 6': 38.35, 27: 'Managerial staff – hotel': 38.41, 28: }, 29: } 30: 31: // Fixed award rules - non-editable, shows how the award works 32: const awardRules = [ 33: { 34: id: 'ordinary', 35: name: 'Ordinary hours (Mon-Fri)', 36: days: ['MON', 'TUE', 'WED', 'THU', 'FRI'], 37: startTime: '07:00', 38: endTime: '19:00', 39: penaltyMultiplier: { permanent: 1.0, casual: 1.0 }, 40: }, 41: { 42: id: 'evening', 43: name: 'Evening rate (Mon-Fri)', 44: days: ['MON', 'TUE', 'WED', 'THU', 'FRI'], 45: startTime: '19:00', 46: endTime: '00:00', 47: penaltyMultiplier: { permanent: 1.25, casual: 1.5 }, 48: }, 49: { 50: id: 'latenight', 51: name: 'Late night (Mon-Fri)', 52: days: ['MON', 'TUE', 'WED', 'THU', 'FRI'], 53: startTime: '00:00', 54: endTime: '07:00', 55: penaltyMultiplier: { permanent: 1.5, casual: 1.75 }, 56: }, 57: { 58: id: 'saturday', 59: name: 'Saturday (all day)', 60: days: ['SAT'], 61: startTime: '00:00', 62: endTime: '00:00', 63: penaltyMultiplier: { permanent: 1.5, casual: 1.75 }, 64: }, 65: { 66: id: 'sunday', 67: name: 'Sunday (all day)', 68: days: ['SUN'], 69: startTime: '00:00', 70: endTime: '00:00', 71: penaltyMultiplier: { permanent: 1.75, casual: 2.0 }, 72: }, 73: { 74: id: 'publicholiday', 75: name: 'Public holiday', 76: days: ['HOL'], 77: startTime: '00:00', 78: endTime: '00:00', 79: penaltyMultiplier: { permanent: 2.5, casual: 2.75 }, 80: }, 81: ] 82: --- 83: 84:
85:
86:
AWARD RATE ESTIMATOR
87:

See how RosterElf interprets the Hospitality Award

88:

89: This is an educational example showing how the Hospitality Award penalty rates work. It demonstrates how RosterElf automatically calculates correct pay rates based on classification level, 90: employment type, and shift times. 91:

92:
93: 94: 95:
96:
97: 98:
99: Important: This is an estimator for demonstration purposes only. Do not use these calculations for actual payroll without verifying against the 100: official Fair Work pay guide 103: and consulting your Award obligations. 104:
105:
106:
107: 108: 109:
110:
111: 112:
113: 114:
115:
116: 117:
118: 125:
126:
127: 128: 129:
130: 131:
132:
133: 134:
135: 148:
149:
150:
151:
152: 153: 154:
155:
156:
157:
Base ordinary rate
158:
Mon-Fri, standard hours
159:
160:
161:
162: $ 163: 24.95 164: /hr 165:
166:
167:
168:
169: 170: 171:
172:

173: 174: Hospitality Award penalty rates 175:

176: 177:
178: 179:
180:
181: 182: 183:
184:

185: 186: Example weekly cost (38 hours) 187:

188: 189:
190: 191:
192: 193:
194: Example total: 195: $1,025.29 196:
197:
198: 199: 200:
201:
202:
203: 204:
205:

Example only - not for payroll use

206:

This is a demonstration of how RosterElf calculates award-compliant rates.

207:
208:
209: 219:
220: 221:
222:
223:
224:

The actual cost for your employees will depend on:

225: 226:
    227:
  • Their specific classification level and employment type
  • 228:
  • Actual hours worked and shift times
  • 229:
  • Any additional allowances, overtime, or enterprise agreement provisions
  • 230:
  • Current award rates (which change annually in July)
  • 231:
232: 233:

For accurate payroll calculations, always:

234: 235:
    236:
  1. 237: Verify current rates with the official Fair Work pay guide 243:
  2. 244:
  3. Confirm your employees' correct award coverage and classification
  4. 245:
  5. Use award interpretation software or consult a payroll professional
  6. 246:
  7. Review your specific enterprise agreement (if applicable)
  8. 247:
248: 249:

Do not rely on this example for actual wage payments.

250:
251:
252:
253:
254: 255: 256:
257: 258:
259:

Stop calculating penalty rates manually

260:

Let RosterElf handle award compliance automatically

261: 262:

263: Manual award calculations are time-consuming and error-prone. One mistake can lead to underpayments, compliance issues, and Fair Work penalties. RosterElf's award interpretation engine does 264: the work for you. 265:

266: 267:
268: 269:
270: 271:
272: 273: 274: No credit card required 275: 276: 277: 278: Full access 279: 280: 281: 282: 24/7 support 283: 284:
285:
286: 287: 288:
289:

How RosterElf automates award calculations

290: 291:
292: 293:
294:
295:
1
296: 297:
298:
Create pay templates
299:

300: Create pay templates for each classification level by adding award-compliant base rates and penalty multipliers. Once configured, RosterElf automatically applies the correct template to 301: each shift based on the employee's classification, shift timing, and employment type. 302:

303: Award interpretation → 304:
305: 306: 307:
308:
309:
2
310: 311:
312:
Define rate rules
313:

314: Configure when different penalty rates apply (evenings, weekends, public holidays). The system automatically detects which rate to use based on shift times and days. 315:

316: Penalty rates guide → 317:
318: 319: 320:
321:
322:
3
323: 324:
325:
Auto-apply to shifts
326:

327: Every rostered shift automatically calculates the correct pay rate based on the employee's classification, employment type, and shift timing. No manual work required. 328:

329: Payroll integration → 330:
331:
332: 333: 334:
335:

Learn more:

336: 343:
344:
345:
346:
347: 348: 573: 574: ```` ## File: src/components/IconExample.astro ````astro 1: --- 2: // Example component showing Lucide icon usage 3: import { ChevronDown, Menu, X, ArrowRight, Calendar, Clock, Users, BarChart, MessageCircle, Settings, FileText, CheckCircle, AlertCircle, Info } from 'lucide-astro' 4: --- 5: 6:
7:
8:

Navigation Icons

9:
10:
11: 12: ChevronDown 13:
14:
15: 16: Menu 17:
18:
19: 20: Close 21:
22:
23: 24: Arrow 25:
26:
27:
28: 29:
30:

Feature Icons

31:
32:
33: 34: Calendar 35:
36:
37: 38: Clock 39:
40:
41: 42: Users 43:
44:
45: 46: Analytics 47:
48:
49: 50: Chat 51:
52:
53: 54: Documents 55:
56:
57:
58: 59:
60:

Status Icons

61:
62:
63: 64: Success 65:
66:
67: 68: Alert 69:
70:
71: 72: Info 73:
74:
75:
76: 77:
78:

Interactive Example

79: 83:
84: 85:
86:

Dropdown Example

87: 91:
92:
93: 94: ```` ## File: src/components/IndustryGrid.astro ````astro 1: --- 2: import { ArrowRight } from 'lucide-astro' 3: import type { ComponentType } from 'astro/types' 4: 5: interface IndustryItem { 6: name: string 7: description: string 8: icon: ComponentType 9: href?: string 10: isActive?: boolean 11: } 12: 13: interface Props { 14: chip?: string 15: title?: string 16: description?: string 17: items: IndustryItem[] 18: background?: 'white' | 'primary' 19: } 20: 21: const { 22: chip = 'INDUSTRIES WE SERVE', 23: title = 'Rostering software for every industry', 24: description = 'Purpose-built workforce management for Australian businesses across hospitality, healthcare, retail, and more.', 25: items, 26: background = 'white', 27: } = Astro.props 28: 29: const bgClass = background === 'white' ? 'bg-white' : 'bg-primary-100' 30: const iconBgClass = background === 'white' ? 'bg-primary-100' : 'bg-white' 31: --- 32: 33:
34:
35:
36: {chip} 37:

{title}

38:

{description}

39:
40: 41:
42: { 43: items.map((item) => { 44: const IconComponent = item.icon 45: return item.isActive && item.href ? ( 46: 47:
48: 49:
50:

{item.name}

51:

{item.description}

52:
53: Learn more 54: 55:
56:
57: ) : ( 58:
59:
60: 61:
62:

{item.name}

63:

{item.description}

64:
Coming soon
65:
66: ) 67: }) 68: } 69:
70:
71:
```` ## File: src/components/IndustryServiceSchema.astro ````astro 1: --- 2: /** 3: * IndustryServiceSchema - Generates schema.org Service markup for industry pages 4: * 5: * This component adds structured data to help search engines understand 6: * that RosterElf offers workforce management services to specific industries. 7: */ 8: 9: interface Props { 10: name: string // e.g., "Hospitality", "Retail", "Healthcare" 11: description: string // Page meta description 12: url: string // Canonical URL path e.g., "/industries/hospitality" 13: image?: string // Hero image URL 14: } 15: 16: const { name, description, url, image } = Astro.props 17: 18: const serviceSchema = { 19: '@context': 'https://schema.org', 20: '@type': 'Service', 21: name: `RosterElf for ${name}`, 22: description: description, 23: url: `https://www.rosterelf.com${url}`, 24: ...(image && { image: `https://www.rosterelf.com${image}` }), 25: provider: { 26: '@type': 'Organization', 27: name: 'RosterElf', 28: url: 'https://www.rosterelf.com', 29: logo: 'https://www.rosterelf.com/images/logos/rosterelf-logo.svg', 30: }, 31: areaServed: { 32: '@type': 'Country', 33: name: 'Australia', 34: }, 35: serviceType: 'Workforce Management Software', 36: category: 'Business Software', 37: hasOfferCatalog: { 38: '@type': 'OfferCatalog', 39: name: 'RosterElf Plans', 40: itemListElement: [ 41: { 42: '@type': 'Offer', 43: itemOffered: { 44: '@type': 'Service', 45: name: 'RosterElf Rostering & HR Software', 46: }, 47: price: '4.00', 48: priceCurrency: 'AUD', 49: priceSpecification: { 50: '@type': 'UnitPriceSpecification', 51: price: '4.00', 52: priceCurrency: 'AUD', 53: unitText: 'per active employee per month', 54: }, 55: }, 56: ], 57: }, 58: } 59: --- 60: 61: ```` ## File: src/components/LiteYouTube.astro ````astro 1: --- 2: interface Props { 3: videoId: string 4: title: string 5: class?: string 6: } 7: 8: const { videoId, title, class: className = '' } = Astro.props 9: --- 10: 11:
12: 19:
20: 21: ```` ## File: src/components/LoginButton.astro ````astro 1: --- 2: /** 3: * LoginButton - Reusable CTA button for logging in 4: * 5: * Automatically sets tracking params: 6: * - landing: entry page name (from PageTracker) 7: * - exit: current page name (from PageTracker) 8: * - element: where the button is placed 9: */ 10: 11: interface Props { 12: element: string 13: class?: string 14: variant?: 'primary' | 'secondary' 15: } 16: 17: const { element, class: className, variant = 'primary' } = Astro.props 18: 19: const primaryClass = 'bg-primary flex h-12.5 shrink-0 items-center justify-center gap-2 rounded px-8 py-3 text-base font-semibold text-white transition-all duration-300 hover:bg-black' 20: const secondaryClass = 'text-primary inline-flex items-center gap-2 font-semibold hover:underline' 21: const variantClass = variant === 'primary' ? primaryClass : secondaryClass 22: const finalClass = className ? `${variantClass} ${className}` : variantClass 23: --- 24: 25: 26: {variant === 'primary' ? 'Login to RosterElf' : 'Login'} 27: 28: 29: ```` ## File: src/components/LogisticsAwardCalculator.astro ````astro 1: --- 2: // Logistics Award Rate Calculator Component 3: // Data from 2025 Road Transport and Distribution Award rates (MA000038) 4: 5: import { AlertTriangle, FileText, Clock, CheckCircle, ChevronDown, User, Calculator, Truck } from 'lucide-astro' 6: import TrialButton from './TrialButton.astro' 7: 8: const ratesData = { 9: weekly: { 10: Transport: { 11: 'Grade 1': 25.65, 12: 'Grade 2': 26.27, 13: 'Grade 3': 26.57, 14: 'Grade 4': 27.04, 15: 'Grade 5': 27.37, 16: 'Grade 6': 27.68, 17: 'Grade 7': 28.09, 18: 'Grade 8': 28.9, 19: 'Grade 9': 29.39, 20: 'Grade 10': 30.12, 21: }, 22: Distribution: { 23: 'Level 1': 26.57, 24: 'Level 2': 27.04, 25: 'Level 3': 28.09, 26: 'Level 4': 29.39, 27: }, 28: }, 29: casual: { 30: Transport: { 31: 'Grade 1': 32.06, 32: 'Grade 2': 32.84, 33: 'Grade 3': 33.21, 34: 'Grade 4': 33.8, 35: 'Grade 5': 34.21, 36: 'Grade 6': 34.6, 37: 'Grade 7': 35.11, 38: 'Grade 8': 36.13, 39: 'Grade 9': 36.74, 40: 'Grade 10': 37.65, 41: }, 42: Distribution: { 43: 'Level 1': 33.21, 44: 'Level 2': 33.8, 45: 'Level 3': 35.11, 46: 'Level 4': 36.74, 47: }, 48: }, 49: } 50: 51: // Fixed award rules - non-editable, shows how the award works 52: const awardRules = [ 53: { 54: id: 'ordinary', 55: name: 'Ordinary hours (Mon-Fri)', 56: days: ['MON', 'TUE', 'WED', 'THU', 'FRI'], 57: startTime: '00:00', 58: endTime: '00:00', 59: penaltyMultiplier: { weekly: 1.0, casual: 1.0 }, 60: }, 61: { 62: id: 'saturday', 63: name: 'Saturday (all day)', 64: days: ['SAT'], 65: startTime: '00:00', 66: endTime: '00:00', 67: penaltyMultiplier: { weekly: 1.5, casual: 1.75 }, 68: }, 69: { 70: id: 'sunday', 71: name: 'Sunday (all day)', 72: days: ['SUN'], 73: startTime: '00:00', 74: endTime: '00:00', 75: penaltyMultiplier: { weekly: 2.0, casual: 2.25 }, 76: }, 77: { 78: id: 'publicholiday', 79: name: 'Public holiday', 80: days: ['HOL'], 81: startTime: '00:00', 82: endTime: '00:00', 83: penaltyMultiplier: { weekly: 2.5, casual: 2.75 }, 84: }, 85: ] 86: --- 87: 88:
89:
90:
AWARD RATE ESTIMATOR
91:

See how RosterElf interprets the Logistics Award

92:

93: This is an educational example showing how the Road Transport and Distribution Award penalty rates work. It demonstrates how RosterElf automatically calculates correct pay rates based on stream 94: (transport or distribution), classification level, employment type, and shift times. 95:

96:
97: 98: 99:
100:
101: 102:
103: Important: This is an estimator for demonstration purposes only. Do not use these calculations for actual payroll without verifying against the 104: official Fair Work pay guide 107: and consulting your Award obligations. Calculator shows ordinary rates only—overtime rates differ (see overtime section below). 108:
109:
110:
111: 112: 113:
114:
115: 116:
117: 118:
119:
120: 121:
122: 129:
130:
131: 132: 133:
134: 135:
136:
137: 138:
139: 146:
147:
148: 149: 150:
151: 152:
153:
154: 155:
156: 162:
163:
164:
165:
166: 167: 168:
169:
170:
171:
Base ordinary rate
172:
Monday to Friday
173:
174:
175:
176: $ 177: 25.65 178: /hr 179:
180:
181:
182:
183: 184: 185:
186:

187: 188: Logistics Award penalty rates 189:

190: 191:
192: 193:
194:
195: 196: 197:
198:

199: 200: Example weekly cost (38 hours) 201:

202: 203:
204: 205:
206: 207:
208: Example total: 209: $974.70 210:
211:
212: 213: 214:
215:
216:
217: 218:
219:

Example only - not for payroll use

220:

This is a demonstration of how RosterElf calculates award-compliant rates.

221:
222:
223: 233:
234: 235:
236:
237:
238:

The actual cost for your employees will depend on:

239: 240:
    241:
  • Their specific classification level and employment type
  • 242:
  • Actual hours worked and shift times
  • 243:
  • Any additional allowances, overtime, or enterprise agreement provisions
  • 244:
  • Current award rates (which change annually in July)
  • 245:
  • Oil distribution workers have different calculation methods (see full rates table)
  • 246:
247: 248:

For accurate payroll calculations, always:

249: 250:
    251:
  1. 252: Verify current rates with the official Fair Work pay guide 258:
  2. 259:
  3. Confirm your employees' correct award coverage and classification
  4. 260:
  5. Use award interpretation software or consult a payroll professional
  6. 261:
  7. Review your specific enterprise agreement (if applicable)
  8. 262:
263: 264:

Do not rely on this example for actual wage payments.

265:
266:
267:
268:
269: 270: 271:
272: 273:
274:

Stop calculating penalty rates manually

275:

Let RosterElf handle award compliance automatically

276: 277:

278: Manual award calculations are time-consuming and error-prone. One mistake can lead to underpayments, compliance issues, and Fair Work penalties. RosterElf's award interpretation engine does 279: the work for you. 280:

281: 282:
283: 284:
285: 286:
287: 288: 289: No credit card required 290: 291: 292: 293: Full access 294: 295: 296: 297: 24/7 support 298: 299:
300:
301: 302: 303:
304:

How RosterElf automates award calculations

305: 306:
307: 308:
309:
310:
1
311: 312:
313:
Create pay templates
314:

315: Create pay templates for each classification level by adding award-compliant base rates and penalty multipliers. Once configured, RosterElf automatically applies the correct template to 316: each shift based on the employee's classification, shift timing, and employment type. 317:

318: Award interpretation → 319:
320: 321: 322:
323:
324:
2
325: 326:
327:
Define rate rules
328:

329: Configure when different penalty rates apply (Saturdays, Sundays, public holidays). The system automatically detects which rate to use based on shift times and days. 330:

331: Penalty rates guide → 332:
333: 334: 335:
336:
337:
3
338: 339:
340:
Auto-apply to shifts
341:

342: Every rostered shift automatically calculates the correct pay rate based on the employee's classification, employment type, and shift timing. No manual work required. 343:

344: Payroll integration → 345:
346:
347: 348: 349:
350:

📚 Learn more:

351: 358:
359:
360:
361:
362: 363: 597: 598: ```` ## File: src/components/LSLCalculator.astro ````astro 1: --- 2: /** 3: * LSLCalculator - NSW Long Service Leave Calculator Component 4: * 5: * Interactive calculator to determine LSL entitlements based on service period 6: * Calculates weeks owed and payment amount for NSW employees 7: * 8: * Props: 9: * - chip: Optional chip label (default: "FREE CALCULATOR") 10: * - title: Calculator title (default: "NSW long service leave calculator") 11: * - description: Calculator description 12: * - background: "primary" | "white" (default: "white") 13: */ 14: 15: interface Props { 16: chip?: string 17: title?: string 18: description?: string 19: background?: 'primary' | 'white' 20: } 21: 22: const { 23: chip = 'FREE CALCULATOR', 24: title = 'NSW long service leave calculator', 25: description = "Calculate your long service leave entitlements based on years of continuous service. Enter your employment dates to see how much LSL you're owed.", 26: background = 'white', 27: } = Astro.props 28: 29: const bgClass = background === 'primary' ? 'bg-primary-100' : 'bg-white' 30: --- 31: 32:
33:
34:
35: {chip} 36:

{title}

37:

{description}

38:
39: 40:
41: 42:
43:

Employment details

44: 45:
46: 47: 53:
54: 55:
56: 57: 58:
59: 60:
61: 62: 67:
68: 69:
70: 71: 80:

Enter gross weekly earnings (for casuals, include loading)

81:
82: 83:
84: 85:
86:
87: 88: 89:
90:

Your LSL entitlement

91: 92:
93: 94:
95: Years of continuous service 96: 10.0 years 97:
98: 99: 100:
101: LSL weeks entitled 102: 8.67 weeks 103:
104: 105: 106:
107: Estimated LSL payment 108: $10,404 109:
110: 111: 112:
113:

114: Congratulations! You've reached the 10-year milestone and are entitled to 8.67 weeks of paid long service leave. 115:

116:
117: 118: 119:
120:

121: Next milestone: 122: At 15 years, you'll be entitled to an additional 4.33 weeks (13 weeks total). 123:

124:
125:
126: 127:
128:

129: Disclaimer: This calculator provides estimates based on the NSW Long Service Leave Act 1955. Actual entitlements may vary based on your specific employment agreement, portable 130: scheme coverage, or pro-rata eligibility. For official calculations, use the 131: NSW Government LSL calculator. 134:

135:
136:
137:
138: 139: 140:
141:

Understanding your LSL entitlement

142:
143:
144:
145:
146: 147: 148: 149:
150: 10 years 151:
152:

First entitlement: 8.67 weeks (2 months) of paid leave

153:
154:
155:
156:
157: 158: 159: 160:
161: 5 years 162:
163:

Pro-rata eligible if employment ends due to illness, dismissal, or other qualifying reasons

164:
165:
166:
167:
168: 169: 170: 171:
172: 15+ years 173:
174:

Additional 4.33 weeks at 15 years, then 4.33 weeks per 5 years thereafter

175:
176:
177:
178:
179:
180: 181: ```` ## File: src/components/MailchimpNewsletter.astro ````astro 1: --- 2: interface Props { 3: title?: string 4: description?: string 5: background?: 'white' | 'primary' 6: } 7: 8: const { 9: title = 'Get notified about new features', 10: description = 'Subscribe to our newsletter to receive product updates, tips, and workforce management insights.', 11: background = 'primary', 12: } = Astro.props 13: 14: const backgroundClass = background === 'white' ? 'bg-white' : 'bg-primary-100' 15: --- 16: 17:
18:
19:

{title}

20:

{description}

21:
27: 34: 35: 38: 41:
42:

No spam. Unsubscribe anytime.

43:
44:
```` ## File: src/components/MeatAwardCalculator.astro ````astro 1: --- 2: // Meat Award Rate Calculator Component 3: // Data from 2025 Meat Industry Award 2020 [MA000059] rates 4: 5: import { AlertTriangle, FileText, Clock, CheckCircle, ChevronDown, User, Calculator } from 'lucide-astro' 6: import TrialButton from './TrialButton.astro' 7: 8: const ratesData = { 9: permanent: { 10: MI1: 24.28, 11: MI2: 25.09, 12: MI3: 25.4, 13: MI4: 25.99, 14: MI5: 26.45, 15: MI6: 26.99, 16: MI7: 28.12, 17: MI8: 29.15, 18: }, 19: casual: { 20: MI1: 30.35, 21: MI2: 31.36, 22: MI3: 31.75, 23: MI4: 32.49, 24: MI5: 33.06, 25: MI6: 33.74, 26: MI7: 35.15, 27: MI8: 36.44, 28: }, 29: } 30: 31: // Fixed award rules - non-editable, shows how the Meat Award works 32: // Note: These are for meat processing establishments 33: const awardRules = [ 34: { 35: id: 'ordinary', 36: name: 'Ordinary hours (Mon-Fri, 6am-8pm)', 37: days: ['MON', 'TUE', 'WED', 'THU', 'FRI'], 38: startTime: '06:00', 39: endTime: '20:00', 40: penaltyMultiplier: { permanent: 1.0, casual: 1.0 }, 41: }, 42: { 43: id: 'afternoon', 44: name: 'Afternoon shift (2pm-midnight)', 45: days: ['MON', 'TUE', 'WED', 'THU', 'FRI'], 46: startTime: '14:00', 47: endTime: '00:00', 48: penaltyMultiplier: { permanent: 1.15, casual: 1.4 }, 49: }, 50: { 51: id: 'night', 52: name: 'Night shift (after midnight)', 53: days: ['MON', 'TUE', 'WED', 'THU', 'FRI'], 54: startTime: '00:00', 55: endTime: '06:00', 56: penaltyMultiplier: { permanent: 1.25, casual: 1.5 }, 57: }, 58: { 59: id: 'fixednight', 60: name: 'Fixed night shift (10pm-6am)', 61: days: ['MON', 'TUE', 'WED', 'THU', 'FRI'], 62: startTime: '22:00', 63: endTime: '06:00', 64: penaltyMultiplier: { permanent: 1.3, casual: 1.55 }, 65: }, 66: { 67: id: 'saturday', 68: name: 'Saturday (all day)', 69: days: ['SAT'], 70: startTime: '00:00', 71: endTime: '00:00', 72: penaltyMultiplier: { permanent: 1.5, casual: 1.5 }, 73: }, 74: { 75: id: 'sunday', 76: name: 'Sunday (all day)', 77: days: ['SUN'], 78: startTime: '00:00', 79: endTime: '00:00', 80: penaltyMultiplier: { permanent: 2.0, casual: 2.0 }, 81: }, 82: { 83: id: 'publicholiday', 84: name: 'Public holiday', 85: days: ['HOL'], 86: startTime: '00:00', 87: endTime: '00:00', 88: penaltyMultiplier: { permanent: 2.0, casual: 2.0 }, 89: }, 90: ] 91: --- 92: 93:
94:
95:
AWARD RATE ESTIMATOR
96:

See how RosterElf interprets the Meat Award

97:

98: This is an educational example showing how the Meat Award penalty rates work for meat processing establishments. It demonstrates how RosterElf automatically calculates correct pay rates based on 99: classification level, employment type, and shift times. 100:

101:
102: 103: 104:
105:
106: 107:
108: Important: This is an estimator for demonstration purposes only. Do not use these calculations for actual payroll without verifying against the 109: official Fair Work pay guide 112: and consulting your Award obligations. 113:
114:
115:
116: 117: 118:
119:
120: 121:
122: Note: This calculator demonstrates meat processing establishment rates. Manufacturing and retail establishments have different rules for span of hours and 123: penalties. See establishment type differences → 124:
125:
126:
127: 128: 129:
130:
131: 132:
133: 134:
135:
136: 137:
138: 145:
146:
147: 148: 149:
150: 151:
152:
153: 154:
155: 168:
169:
170:
171:
172: 173: 174:
175:
176:
177:
Base ordinary rate
178:
Mon-Fri, standard hours
179:
180:
181:
182: $ 183: 24.28 184: /hr 185:
186:
187:
188:
189: 190: 191:
192:

193: 194: Meat Award penalty rates (processing establishments) 195:

196: 197:
198: 199:
200:
201: 202: 203:
204:

205: 206: Example weekly cost (38 hours) 207:

208: 209:
210: 211:
212: 213:
214: Example total: 215: $1,089.00 216:
217:
218: 219: 220:
221:
222:
223: 224:
225:

Example only - not for payroll use

226:

This is a demonstration of how RosterElf calculates award-compliant rates.

227:
228:
229: 239:
240: 241:
242:
243:
244:

The actual cost for your employees will depend on:

245: 246:
    247:
  • Their specific classification level and employment type
  • 248:
  • Actual hours worked and shift times
  • 249:
  • Which type of establishment (processing, manufacturing, or retail)
  • 250:
  • Any additional allowances, overtime, or enterprise agreement provisions
  • 251:
  • Current award rates (which change annually in July)
  • 252:
  • Junior rates if the employee is under 21
  • 253:
254: 255:

For accurate payroll calculations, always:

256: 257:
    258:
  1. 259: Verify current rates with the official Fair Work pay guide 265:
  2. 266:
  3. Confirm your employees' correct award coverage and classification
  4. 267:
  5. Use award interpretation software or consult a payroll professional
  6. 268:
  7. Review your specific enterprise agreement (if applicable)
  8. 269:
270: 271:

Do not rely on this example for actual wage payments.

272:
273:
274:
275:
276: 277: 278:
279: 280:
281:

Stop calculating penalty rates manually

282:

Let RosterElf handle award compliance automatically

283: 284:

285: Manual award calculations are time-consuming and error-prone. One mistake can lead to underpayments, compliance issues, and Fair Work penalties. RosterElf's award interpretation engine does 286: the work for you. 287:

288: 289:
290: 291:
292: 293:
294: 295: 296: No credit card required 297: 298: 299: 300: Full access 301: 302: 303: 304: 24/7 support 305: 306:
307:
308: 309: 310:
311:

How RosterElf automates award calculations

312: 313:
314: 315:
316:
317:
1
318: 319:
320:
Create pay templates
321:

322: Create pay templates for each classification level by adding award-compliant base rates and penalty multipliers. Once configured, RosterElf automatically applies the correct template to 323: each shift based on the employee's classification, shift timing, and employment type. 324:

325: Award interpretation → 326:
327: 328: 329:
330:
331:
2
332: 333:
334:
Define rate rules
335:

336: Configure when different penalty rates apply (late nights, weekends, public holidays). The system automatically detects which rate to use based on shift times and days. 337:

338: Penalty rates guide → 339:
340: 341: 342:
343:
344:
3
345: 346:
347:
Auto-apply to shifts
348:

349: Every rostered shift automatically calculates the correct pay rate based on the employee's classification, employment type, and shift timing. No manual work required. 350:

351: Payroll integration → 352:
353:
354: 355: 356:
357:

Learn more:

358: 365:
366:
367:
368:
369: 370: 596: 597: ```` ## File: src/components/NursesAwardCalculator.astro ````astro 1: --- 2: // Nurses Award Rate Calculator Component 3: // Data from 2025/26 Nurses Award rates (MA000034) 4: 5: import { AlertTriangle, FileText, Clock, CheckCircle, ChevronDown } from 'lucide-astro' 6: import TrialButton from './TrialButton.astro' 7: 8: const ratesData = { 9: nonAgedCare: { 10: permanent: { 11: 'EN PP1': 28.64, 12: 'EN PP3': 29.4, 13: 'EN PP5': 30.13, 14: 'RN L1 PP1': 30.64, 15: 'RN L1 PP4': 33.09, 16: 'RN L1 PP8': 36.82, 17: 'RN L2 PP1': 37.79, 18: 'RN L2 PP4': 39.7, 19: 'RN L3 PP1': 40.98, 20: 'RN L3 PP4': 43.21, 21: 'RN L4': 46.77, 22: 'RN L5': 47.19, 23: }, 24: casual: {}, 25: }, 26: agedCare: { 27: permanent: { 28: EN: 37.09, 29: 'RN L1 (first year)': 38.07, 30: 'RN L1 (1-4 years)': 40.0, 31: 'RN L1 (>4 years)': 43.72, 32: 'RN L2 (first 3 years)': 47.34, 33: 'RN L2 (>3 years)': 49.48, 34: 'RN L3': 51.21, 35: 'RN L4': 59.19, 36: 'RN L5': 66.91, 37: }, 38: casual: {}, 39: }, 40: } 41: 42: // Calculate casual rates (25% loading) 43: for (const sector of ['nonAgedCare', 'agedCare']) { 44: for (const level in ratesData[sector].permanent) { 45: ratesData[sector].casual[level] = Number((ratesData[sector].permanent[level] * 1.25).toFixed(2)) 46: } 47: } 48: 49: // Fixed award rules - non-editable, shows how the award works 50: const awardRules = [ 51: { 52: id: 'ordinary', 53: name: 'Ordinary hours (Mon-Fri)', 54: days: ['MON', 'TUE', 'WED', 'THU', 'FRI'], 55: startTime: '07:00', 56: endTime: '18:00', 57: penaltyMultiplier: { permanent: 1.0, casual: 1.0 }, 58: }, 59: { 60: id: 'saturday', 61: name: 'Saturday (all day)', 62: days: ['SAT'], 63: startTime: '00:00', 64: endTime: '00:00', 65: penaltyMultiplier: { permanent: 1.5, casual: 1.75 }, 66: }, 67: { 68: id: 'sunday', 69: name: 'Sunday (all day)', 70: days: ['SUN'], 71: startTime: '00:00', 72: endTime: '00:00', 73: penaltyMultiplier: { permanent: 1.75, casual: 2.0 }, 74: }, 75: { 76: id: 'publicholiday', 77: name: 'Public holiday', 78: days: ['HOL'], 79: startTime: '00:00', 80: endTime: '00:00', 81: penaltyMultiplier: { permanent: 2.5, casual: 2.75 }, 82: }, 83: ] 84: --- 85: 86:
87:
88:
AWARD RATE ESTIMATOR
89:

See how RosterElf interprets the Nurses Award

90:

91: This is an educational example showing how the Nurses Award penalty rates work. It demonstrates how RosterElf automatically calculates correct pay rates based on classification level, employment 92: type, care setting, and shift times. 93:

94:
95: 96: 97:
98:
99: 100:
101: Important: This is an estimator for demonstration purposes only. Do not use these calculations for actual payroll without verifying against the 102: official Fair Work pay guide 105: and consulting your Award obligations. 106:
107:
108:
109: 110: 111:
112:
113: 114:
115: 116:
117:
118: 119: 124: 125:
126: 133:
134:
135: 136: 137:
138: 139:
140:
141: 142: 143: 144:
145: 152:
153:
154: 155: 156:
157: 158:
159:
160: 161: 166: 167:
168: 174:
175:
176:
177:
178: 179: 180:
181:
182:
183:
Base ordinary rate
184:
Mon-Fri, standard hours
185:
186:
187:
188: $ 189: 38.07 190: /hr 191:
192:
193:
194:
195: 196: 197:
198:

199: 200: 201: 202: Nurses Award penalty rates 203:

204: 205:
206: 207:
208:
209: 210: 211:
212:

213: 214: 219: 220: Example weekly cost (38 hours) 221:

222: 223:
224: 225:
226: 227:
228: Example total: 229: $1,558.82 230:
231:
232: 233: 234:
235:
236:
237: 238:
239:

Example only - not for payroll use

240:

This is a demonstration of how RosterElf calculates award-compliant rates.

241:
242:
243: 253:
254: 255:
256:
257:
258:

The actual cost for your employees will depend on:

259: 260:
    261:
  • Their specific classification level, employment type, and care setting
  • 262:
  • Actual hours worked and shift times (including evening and night penalties)
  • 263:
  • Any additional allowances (meal, in-charge, on-call), overtime, or enterprise agreement provisions
  • 264:
  • Current award rates (which change annually in July, with aged care increases in October)
  • 265:
266: 267:

For accurate payroll calculations, always:

268: 269:
    270:
  1. 271: Verify current rates with the official Fair Work MA000034 summary 277:
  2. 278:
  3. Confirm your employees' correct award coverage, classification, and care setting
  4. 279:
  5. Use award interpretation software or consult a payroll professional
  6. 280:
  7. Check for preserved higher rates under Schedule F (especially aged care RN L4/L5)
  8. 281:
282: 283:

Do not rely on this example for actual wage payments.

284:
285:
286:
287:
288: 289: 290:
291: 292:
293:

Stop calculating nursing penalty rates manually

294:

Let RosterElf handle award compliance automatically

295: 296:

297: Manual award calculations are time-consuming and error-prone. Missing the aged care wage increase or applying wrong penalty rates can lead to underpayments, compliance issues, and Fair Work 298: penalties. RosterElf's award interpretation engine does the work for you. 299:

300: 301:
302: 303:
304: 305:
306: 307: 308: No credit card required 309: 310: 311: 312: Full access 313: 314: 315: 316: 24/7 support 317: 318:
319:
320: 321: 322:
323:

How RosterElf automates nursing award calculations

324: 325:
326: 327:
328:
329:
1
330: 331:
332:
Set up nursing pay templates
333:

334: Create pay templates for each RN/EN classification and care setting (aged care vs other). Configure base rates with the correct aged care increases from October 2025. RosterElf 335: automatically applies the correct template to each shift based on the employee's classification and work location. 336:

337: Award interpretation → 338:
339: 340: 341:
342:
343:
2
344: 345:
346:
Define nursing penalty rules
347:

348: Configure weekend penalties (Saturday 150%, Sunday 175%), public holidays (250%), and evening/night shift loadings. The system automatically detects which rate to use based on shift times 349: and days. 350:

351: Nurses Award guide → 352:
353: 354: 355:
356:
357:
3
358: 359:
360:
Auto-apply to shifts
361:

362: Every rostered shift automatically calculates the correct pay rate based on the nurse's classification, employment type, care setting, and shift timing. No manual calculations required. 363:

364: Payroll integration → 365:
366:
367: 368: 369:
370:

📚 Learn more:

371: 378:
379:
380:
381:
382: 383: 658: 659: ```` ## File: src/components/OccupationSchema.astro ````astro 1: --- 2: /** 3: * OccupationSchema Component 4: * Generates schema.org Occupation markup for job description template pages 5: * This is for describing job roles/occupations, NOT for actual job postings 6: */ 7: 8: interface Responsibility { 9: title: string 10: description: string 11: } 12: 13: interface Skill { 14: title: string 15: description: string 16: } 17: 18: interface Qualification { 19: name: string 20: required: boolean 21: description: string 22: } 23: 24: interface Props { 25: name: string // e.g., "Bartender" 26: description: string 27: responsibilities?: Responsibility[] 28: skills?: Skill[] 29: qualifications?: Qualification[] 30: industry?: string // e.g., "Hospitality" 31: employmentType?: string[] // e.g., ["FULL_TIME", "PART_TIME", "CASUAL"] 32: } 33: 34: const { name, description, responsibilities = [], skills = [], qualifications = [], industry, employmentType = ['FULL_TIME', 'PART_TIME'] } = Astro.props 35: 36: const schema = { 37: '@context': 'https://schema.org', 38: '@type': 'Occupation', 39: name: name, 40: description: description, 41: ...(responsibilities.length > 0 && { 42: responsibilities: responsibilities.map((r) => r.description).join('. '), 43: }), 44: ...(skills.length > 0 && { 45: skills: skills.map((s) => s.title).join(', '), 46: }), 47: ...(qualifications.length > 0 && { 48: qualifications: qualifications 49: .filter((q) => q.required) 50: .map((q) => q.name) 51: .join(', '), 52: }), 53: ...(industry && { 54: occupationalCategory: industry, 55: }), 56: occupationLocation: { 57: '@type': 'Country', 58: name: 'Australia', 59: }, 60: estimatedSalary: { 61: '@type': 'MonetaryAmountDistribution', 62: name: 'Base salary', 63: currency: 'AUD', 64: duration: 'P1H', 65: description: 'Hourly rate based on applicable Modern Award', 66: }, 67: } 68: --- 69: 70: ```` ## File: src/components/PastoralAwardCalculator.astro ````astro 1: --- 2: // Pastoral Award Rate Calculator Component 3: // Data from 2025 Pastoral Award rates 4: 5: import { AlertTriangle, FileText, Clock, CheckCircle, ChevronDown, User, Calculator } from 'lucide-astro' 6: import TrialButton from './TrialButton.astro' 7: 8: const ratesData = { 9: permanent: { 10: FLH1: 24.28, 11: FLH2: 24.95, 12: FLH3: 25.29, 13: FLH4: 25.85, 14: FLH5: 26.3, 15: FLH6: 26.7, 16: FLH7: 28.12, 17: FLH8: 30.21, 18: }, 19: casual: { 20: FLH1: 30.35, 21: FLH2: 31.19, 22: FLH3: 31.61, 23: FLH4: 32.31, 24: FLH5: 32.88, 25: FLH6: 33.38, 26: FLH7: 35.15, 27: FLH8: 37.76, 28: }, 29: } 30: 31: // Fixed award rules - non-editable, shows how the award works 32: const awardRules = [ 33: { 34: id: 'ordinary', 35: name: 'Ordinary hours (Mon-Sat)', 36: days: ['MON', 'TUE', 'WED', 'THU', 'FRI', 'SAT'], 37: startTime: '00:00', 38: endTime: '00:00', 39: penaltyMultiplier: { permanent: 1.0, casual: 1.0 }, 40: }, 41: { 42: id: 'overtime-mon-sat', 43: name: 'Overtime (Mon-Sat)', 44: days: ['MON', 'TUE', 'WED', 'THU', 'FRI', 'SAT'], 45: startTime: '00:00', 46: endTime: '00:00', 47: penaltyMultiplier: { permanent: 1.5, casual: 1.75 }, 48: }, 49: { 50: id: 'sunday-feeding', 51: name: 'Sunday - feeding & watering stock', 52: days: ['SUN'], 53: startTime: '00:00', 54: endTime: '00:00', 55: penaltyMultiplier: { permanent: 1.5, casual: 1.75 }, 56: }, 57: { 58: id: 'sunday-other', 59: name: 'Sunday - other work', 60: days: ['SUN'], 61: startTime: '00:00', 62: endTime: '00:00', 63: penaltyMultiplier: { permanent: 2.0, casual: 2.25 }, 64: }, 65: { 66: id: 'publicholiday', 67: name: 'Public holiday', 68: days: ['HOL'], 69: startTime: '00:00', 70: endTime: '00:00', 71: penaltyMultiplier: { permanent: 2.0, casual: 2.25 }, 72: }, 73: ] 74: --- 75: 76:
77:
78:
AWARD RATE ESTIMATOR
79:

See how RosterElf interprets the Pastoral Award

80:

81: This is an educational example showing how the Pastoral Award penalty rates work. It demonstrates how RosterElf automatically calculates correct pay rates based on classification level, 82: employment type, and shift times. 83:

84:
85: 86: 87:
88:
89: 90:
91: Important: This is an estimator for demonstration purposes only. Do not use these calculations for actual payroll without verifying against the 92: official Fair Work pay guide 95: and consulting your Award obligations. 96:
97:
98:
99: 100: 101:
102:
103: 104:
105: 106:
107:
108: 109:
110: 117:
118:
119: 120: 121:
122: 123:
124:
125: 126:
127: 140:
141:
142:
143:
144: 145: 146:
147:
148:
149:
Base ordinary rate
150:
Mon-Sat, ordinary hours
151:
152:
153:
154: $ 155: 24.95 156: /hr 157:
158:
159:
160:
161: 162: 163:
164:

165: 166: Pastoral Award penalty rates 167:

168: 169:
170: 171:
172:
173: 174: 175:
176:

177: 178: Example weekly cost (38 hours) 179:

180: 181:
182: 183:
184: 185:
186: Example total: 187: $1,047.90 188:
189:
190: 191: 192:
193:
194:
195: 196:
197:

Example only - not for payroll use

198:

This is a demonstration of how RosterElf calculates award-compliant rates.

199:
200:
201: 211:
212: 213:
214:
215:
216:

The actual cost for your employees will depend on:

217: 218:
    219:
  • Their specific classification level and employment type
  • 220:
  • Actual hours worked and shift times
  • 221:
  • Any additional allowances, overtime, or enterprise agreement provisions
  • 222:
  • Current award rates (which change annually in July)
  • 223:
224: 225:

For accurate payroll calculations, always:

226: 227:
    228:
  1. 229: Verify current rates with the official Fair Work pay guide 235:
  2. 236:
  3. Confirm your employees' correct award coverage and classification
  4. 237:
  5. Use award interpretation software or consult a payroll professional
  6. 238:
  7. Review your specific enterprise agreement (if applicable)
  8. 239:
240: 241:

Do not rely on this example for actual wage payments.

242:
243:
244:
245:
246: 247: 248:
249: 250:
251:

Stop calculating penalty rates manually

252:

Let RosterElf handle award compliance automatically

253: 254:

255: Manual award calculations are time-consuming and error-prone. One mistake can lead to underpayments, compliance issues, and Fair Work penalties. RosterElf's award interpretation engine does 256: the work for you. 257:

258: 259:
260: 261:
262: 263:
264: 265: 266: No credit card required 267: 268: 269: 270: Full access 271: 272: 273: 274: 24/7 support 275: 276:
277:
278: 279: 280:
281:

How RosterElf automates award calculations

282: 283:
284: 285:
286:
287:
1
288: 289:
290:
Create pay templates
291:

292: Create pay templates for each classification level by adding award-compliant base rates and penalty multipliers. Once configured, RosterElf automatically applies the correct template to 293: each shift based on the employee's classification, shift timing, and employment type. 294:

295: Award interpretation → 296:
297: 298: 299:
300:
301:
2
302: 303:
304:
Define rate rules
305:

306: Configure when different penalty rates apply (overtime, Sundays, public holidays). The system automatically detects which rate to use based on shift times and days. 307:

308: Penalty rates guide → 309:
310: 311: 312:
313:
314:
3
315: 316:
317:
Auto-apply to shifts
318:

319: Every rostered shift automatically calculates the correct pay rate based on the employee's classification, employment type, and shift timing. No manual work required. 320:

321: Payroll integration → 322:
323:
324: 325: 326:
327:

Learn more:

328: 335:
336:
337:
338:
339: 340: 565: 566: ```` ## File: src/components/PlumbingAwardCalculator.astro ````astro 1: --- 2: // Plumbing Award Rate Calculator Component 3: // Data from 2025 Plumbing and Fire Sprinklers Award rates (MA000036) 4: 5: import { AlertTriangle, FileText, Clock, CheckCircle, ChevronDown, User, Calculator } from 'lucide-astro' 6: import TrialButton from './TrialButton.astro' 7: 8: const ratesData = { 9: weekly: { 10: 'Worker Level 1(a)': 26.71, 11: 'Worker Level 1(b)': 27.6, 12: 'Worker Level 1(c)': 28.48, 13: 'Tradesperson Level 1': 30.45, 14: 'Tradesperson Level 1 (registered)': 31.33, 15: 'Advanced Tradesperson Level 2': 34.57, 16: 'Advanced Tradesperson Level 2 (registered)': 35.45, 17: }, 18: casual: { 19: 'Worker Level 1(a)': 33.39, 20: 'Worker Level 1(b)': 34.5, 21: 'Worker Level 1(c)': 35.6, 22: 'Tradesperson Level 1': 38.06, 23: 'Tradesperson Level 1 (registered)': 39.16, 24: 'Advanced Tradesperson Level 2': 43.21, 25: 'Advanced Tradesperson Level 2 (registered)': 44.31, 26: }, 27: } 28: 29: // Fixed award rules - non-editable, shows how the award works 30: const awardRules = [ 31: { 32: id: 'ordinary', 33: name: 'Ordinary hours (Mon-Fri)', 34: days: ['MON', 'TUE', 'WED', 'THU', 'FRI'], 35: startTime: '07:00', 36: endTime: '18:00', 37: penaltyMultiplier: { weekly: 1.0, casual: 1.0 }, 38: }, 39: { 40: id: 'saturday-first', 41: name: 'Saturday (first 2 hours)', 42: days: ['SAT'], 43: startTime: '00:00', 44: endTime: '02:00', 45: penaltyMultiplier: { weekly: 1.5, casual: 1.75 }, 46: }, 47: { 48: id: 'saturday-after', 49: name: 'Saturday (after 2 hours)', 50: days: ['SAT'], 51: startTime: '02:00', 52: endTime: '00:00', 53: penaltyMultiplier: { weekly: 2.0, casual: 2.25 }, 54: }, 55: { 56: id: 'sunday', 57: name: 'Sunday (all day)', 58: days: ['SUN'], 59: startTime: '00:00', 60: endTime: '00:00', 61: penaltyMultiplier: { weekly: 2.0, casual: 2.25 }, 62: }, 63: { 64: id: 'publicholiday', 65: name: 'Public holiday', 66: days: ['HOL'], 67: startTime: '00:00', 68: endTime: '00:00', 69: penaltyMultiplier: { weekly: 2.5, casual: 2.75 }, 70: }, 71: ] 72: --- 73: 74:
75:
76:
AWARD RATE ESTIMATOR
77:

See how RosterElf interprets the Plumbing Award

78:

79: This is an educational example showing how the Plumbing and Fire Sprinklers Award penalty rates work. It demonstrates how RosterElf automatically calculates correct pay rates based on 80: classification level, employment type, and shift times. 81:

82:
83: 84: 85:
86:
87: 88:
89: Important: This is an estimator for demonstration purposes only. Do not use these calculations for actual payroll without verifying against the 90: official Fair Work pay guide 93: and consulting your Award obligations. 94:
95:
96:
97: 98: 99:
100:
101: 102:
103: 104:
105:
106: 107:
108: 115:
116:
117: 118: 119:
120: 121:
122:
123: 124:
125: 137:
138:
139:
140:
141: 142: 143:
144:
145:
146:
Base ordinary rate
147:
Mon-Fri, standard hours
148:
149:
150:
151: $ 152: 26.71 153: /hr 154:
155:
156:
157:
158: 159: 160:
161:

162: 163: Plumbing Award penalty rates 164:

165: 166:
167: 168:
169:
170: 171: 172:
173:

174: 175: Example weekly cost (38 hours) 176:

177: 178:
179: 180:
181: 182:
183: Example total: 184: $1,014.98 185:
186:
187: 188: 189:
190:
191:
192: 193:
194:

Example only - not for payroll use

195:

This is a demonstration of how RosterElf calculates award-compliant rates.

196:
197:
198: 208:
209: 210:
211:
212:
213:

The actual cost for your employees will depend on:

214: 215:
    216:
  • Their specific classification level and employment type
  • 217:
  • Actual hours worked and shift times
  • 218:
  • Any additional allowances, overtime, or enterprise agreement provisions
  • 219:
  • RDO accrual and arrangements
  • 220:
  • Current award rates (which change annually in July)
  • 221:
222: 223:

For accurate payroll calculations, always:

224: 225:
    226:
  1. 227: Verify current rates with the official Fair Work pay guide 233:
  2. 234:
  3. Confirm your employees' correct award coverage and classification
  4. 235:
  5. Use award interpretation software or consult a payroll professional
  6. 236:
  7. Review your specific enterprise agreement (if applicable)
  8. 237:
238: 239:

Do not rely on this example for actual wage payments.

240:
241:
242:
243:
244: 245: 246:
247: 248:
249:

Stop calculating penalty rates manually

250:

Let RosterElf handle award compliance automatically

251: 252:

253: Manual award calculations are time-consuming and error-prone. One mistake can lead to underpayments, compliance issues, and Fair Work penalties. RosterElf's award interpretation engine does 254: the work for you. 255:

256: 257:
258: 259:
260: 261:
262: 263: 264: No credit card required 265: 266: 267: 268: Full access 269: 270: 271: 272: 24/7 support 273: 274:
275:
276: 277: 278:
279:

How RosterElf automates award calculations

280: 281:
282: 283:
284:
285:
1
286: 287:
288:
Create pay templates
289:

290: Create pay templates for each classification level by adding award-compliant base rates and penalty multipliers. Once configured, RosterElf automatically applies the correct template to 291: each shift based on the employee's classification, shift timing, and employment type. 292:

293: Award interpretation → 294:
295: 296: 297:
298:
299:
2
300: 301:
302:
Define rate rules
303:

304: Configure when different penalty rates apply (Saturdays with 2-hour split, Sundays, public holidays). The system automatically detects which rate to use based on shift times and days. 305:

306: Penalty rates guide → 307:
308: 309: 310:
311:
312:
3
313: 314:
315:
Auto-apply to shifts
316:

317: Every rostered shift automatically calculates the correct pay rate based on the employee's classification, employment type, and shift timing. No manual work required. 318:

319: Payroll integration → 320:
321:
322: 323: 324:
325:

📚 Learn more:

326: 333:
334:
335:
336:
337: 338: 563: 564: ```` ## File: src/components/PopularIndustriesSection.astro ````astro 1: --- 2: import { ArrowRight, Hotel, UtensilsCrossed, Coffee, Stethoscope, Heart, ShoppingBag, ShoppingCart, Baby } from 'lucide-astro' 3: 4: interface Props { 5: background?: 'white' | 'primary' 6: title?: string 7: subtitle?: string 8: } 9: 10: const { background = 'primary', title = 'Popular industries we serve', subtitle = 'RosterElf is trusted by shift-based businesses across Australia' } = Astro.props 11: 12: // Curated list of popular industries for feature pages - mix of hubs and high-traffic sub-industries 13: const popularIndustries = [ 14: { name: 'Hospitality', slug: 'hospitality', description: 'Hotels, pubs, bars & venues', icon: Hotel }, 15: { name: 'Restaurants', slug: 'restaurants', description: 'Dining & food service', icon: UtensilsCrossed }, 16: { name: 'Cafes', slug: 'cafe', description: 'Coffee shops & bakeries', icon: Coffee }, 17: { name: 'Healthcare', slug: 'healthcare', description: 'Medical & allied health', icon: Stethoscope }, 18: { name: 'Aged care', slug: 'aged-care', description: 'Residential & home care', icon: Heart }, 19: { name: 'Retail', slug: 'retail', description: 'Shops & stores', icon: ShoppingBag }, 20: { name: 'Supermarkets', slug: 'supermarkets', description: 'Grocery & convenience', icon: ShoppingCart }, 21: { name: 'Childcare', slug: 'childcare', description: 'Early learning centres', icon: Baby }, 22: ] 23: 24: const bgClass = background === 'white' ? 'bg-white' : 'bg-primary-100' 25: --- 26: 27:
28:
29:
30: INDUSTRIES 31:

{title}

32:

{subtitle}

33:
34: 35:
36: { 37: popularIndustries.map((industry) => { 38: const IconComponent = industry.icon 39: return ( 40: 41:
42: 43:
44:
45: {industry.name} 46: {industry.description} 47:
48:
49: ) 50: }) 51: } 52:
53: 54: 55: View all industries 56: 57: 58:
59:
```` ## File: src/components/PremiereGate.astro ````astro 1: --- 2: /** 3: * PremiereGate Component 4: * Prevents page from being accessed if premiere date hasn't passed 5: * Does server-side redirect to 404 for unpublished content (SEO-friendly) 6: * Preview mode: Add ?preview=true to URL to view unpublished content 7: * 8: * Usage at the TOP of your page: 9: * --- 10: * import PremiereGate from '../components/PremiereGate.astro' 11: * export const premiereDate = '2025-01-15' 12: * --- 13: * 14: * 15: * 16: * 17: * 18: */ 19: 20: interface Props { 21: premiereDate?: string 22: showBadge?: boolean 23: } 24: 25: const { premiereDate, showBadge = false } = Astro.props 26: 27: // Determine if page should be visible based on date 28: let isVisible = true 29: let formattedDate = '' 30: let isPreviewMode = false 31: 32: if (premiereDate) { 33: const now = new Date() 34: const premiere = new Date(premiereDate) 35: 36: // Compare dates at midnight 37: now.setHours(0, 0, 0, 0) 38: premiere.setHours(0, 0, 0, 0) 39: 40: isVisible = premiere <= now 41: 42: // Check for preview mode (server-side) 43: isPreviewMode = Astro.url.searchParams.has('preview') 44: 45: formattedDate = premiere.toLocaleDateString('en-AU', { 46: year: 'numeric', 47: month: 'long', 48: day: 'numeric', 49: }) 50: 51: // Server-side redirect to 404 if not visible and not in preview mode 52: if (!isVisible && !isPreviewMode) { 53: return Astro.redirect('/404', 404) 54: } 55: } 56: --- 57: 58: {/* Page is either visible or in preview mode */} 59: <> 60: {showBadge && premiereDate && isVisible && ( 61:
62: 63: 64: 65: Published {formattedDate} 66:
67: )} 68: 69: 70: ```` ## File: src/components/PremiereLink.astro ````astro 1: --- 2: /** 3: * PremiereLink Component 4: * Wrapper that shows/hides content based on premiere date 5: * Checks at build time - content not rendered if date hasn't passed 6: * 7: * Usage: 8: * 9: * New Feature 10: * 11: * 12: * 13: *
...
14: *
15: * 16: * 17: * 18: * 19: * 20: * Date format: YYYY-MM-DD 21: */ 22: 23: interface Props { 24: premiereDate: string 25: } 26: 27: const { premiereDate } = Astro.props 28: 29: // Check if premiere date has passed 30: const now = new Date() 31: const premiere = new Date(premiereDate) 32: 33: now.setHours(0, 0, 0, 0) 34: premiere.setHours(0, 0, 0, 0) 35: 36: const isVisible = premiere <= now 37: --- 38: 39: {isVisible ? : null} ```` ## File: src/components/PricingCards.astro ````astro 1: --- 2: /** 3: * PricingCards Component 4: * 5: * Reusable pricing cards that pull from centralized pricingData.ts 6: * Can be used on pricing page, comparison pages, etc. 7: * 8: * Props: 9: * - variant: 'full' (3 cards) | 'compact' (simplified for embedding) 10: * - showToggle: whether to show billing toggle (default: true) 11: * - background: 'white' | 'primary' (default: 'primary') 12: */ 13: 14: import { Check, ChevronRight, Star, CalendarClock, Layers, Users } from 'lucide-astro' 15: import { pricingRates, plans, minimumMonthlySpend, annualDiscountPercent } from '../data/pricingData' 16: import TrialButton from './TrialButton.astro' 17: 18: interface Props { 19: variant?: 'full' | 'compact' 20: showToggle?: boolean 21: background?: 'white' | 'primary' 22: defaultBilling?: 'monthly' | 'annual' 23: currencySymbol?: string 24: currencyCode?: string 25: taxLabel?: string 26: taxPrefix?: string 27: rates?: typeof pricingRates 28: minimumSpend?: number 29: contactHref?: string 30: planFeatures?: Record 31: planTaglines?: Record 32: planDescriptions?: Record 33: planLinks?: Record 34: } 35: 36: const { 37: variant = 'full', 38: showToggle = true, 39: background = 'primary', 40: defaultBilling = 'monthly', 41: currencySymbol = '$', 42: currencyCode = 'AUD', 43: taxLabel = 'GST', 44: taxPrefix = '+', 45: rates = pricingRates, 46: minimumSpend = minimumMonthlySpend, 47: contactHref = '/why-rosterelf', 48: planFeatures, 49: planTaglines, 50: planDescriptions, 51: planLinks, 52: } = Astro.props 53: 54: const bgClass = background === 'white' ? 'bg-white' : 'bg-primary-100' 55: const isCompact = variant === 'compact' 56: 57: // Icon mapping 58: const planIcons = { 59: core: CalendarClock, 60: fullSuite: Layers, 61: hr: Users, 62: } 63: 64: // Generate unique IDs for this instance (for multiple components on same page) 65: const instanceId = Math.random().toString(36).substring(7) 66: --- 67: 68:
69:
70: { 71: showToggle && ( 72:
73:
74: 84: 94:
95:

96: Save {annualDiscountPercent}% with annual billing 97:

98:
99: ) 100: } 101: 102:
103: { 104: plans.map((plan) => { 105: const Icon = planIcons[plan.id] 106: const isPopular = plan.popular 107: 108: return ( 109:
110: {isPopular && ( 111:
112: MOST POPULAR 113:
114: )} 115: 116:

117: 118: {plan.name} 119:

120:

{planTaglines?.[plan.id] ?? plan.tagline}

121:

{planDescriptions?.[plan.id] ?? plan.description}

122: 123:
124: 125: {currencySymbol} 126: 127: {defaultBilling === 'monthly' ? rates[plan.id].monthly.toFixed(2) : rates[plan.id].annual.toFixed(2)} 128: 129: 130: {currencyCode} 131:
132:

per employee per month

133:

134: {taxPrefix} {taxLabel}, billed {defaultBilling === 'annual' ? 'annually' : 'monthly'} 135:

136: 137: 138: 139: {!isCompact && ( 140: <> 141:

{plan.id === 'fullSuite' ? 'Everything in Core, plus:' : `${plan.name} features:`}

142:
    143: {(planFeatures?.[plan.id] ?? plan.features).map((feature) => ( 144:
  • 145: 146: {feature} 147:
  • 148: ))} 149:
150: 151: )} 152: 153: 154: See all features 155: 156:
157: ) 158: }) 159: } 160:
161: 162:

163: {currencySymbol}{minimumSpend} minimum monthly spend applies to all plans. All prices exclude {taxLabel}. 164: Contact us for enterprise pricing (250+ employees). 165:

166:
167:
168: 169: ```` ## File: src/components/RatingsSection.astro ````astro 1: --- 2: import { Star } from 'lucide-astro' 3: import { ratingsData, roundRating } from '../data/ratingsData' 4: 5: interface Props { 6: background?: 'primary' | 'white' 7: } 8: 9: const { background = 'primary' } = Astro.props 10: const bgClass = background === 'primary' ? 'bg-primary-100' : 'bg-white' 11: 12: // Rating data from centralized source with platform logos 13: const ratings = [ 14: { name: ratingsData.platforms.xero.name, logo: '/images/logos/xero-app-store.svg', rating: ratingsData.platforms.xero.rating, width: 130, url: ratingsData.platforms.xero.url }, 15: { name: ratingsData.platforms.google.name, logo: '/images/logos/google.png', rating: ratingsData.platforms.google.rating, width: 130, url: ratingsData.platforms.google.url }, 16: { name: ratingsData.platforms.g2.name, logo: '/images/logos/g2-review.webp', rating: ratingsData.platforms.g2.rating, width: 150, url: ratingsData.platforms.g2.url }, 17: { name: ratingsData.platforms.capterra.name, logo: '/images/logos/capterra.svg', rating: ratingsData.platforms.capterra.rating, width: 150, url: ratingsData.platforms.capterra.url }, 18: ] 19: 20: // Aggregate rating for mobile display 21: const avgRating = ratingsData.aggregate.averageRating 22: 23: // Helper to generate star fill percentages 24: const getStarFills = (rating: number) => { 25: const fills = [] 26: for (let i = 1; i <= 5; i++) { 27: if (rating >= i) { 28: fills.push(100) // Full star 29: } else if (rating > i - 1) { 30: fills.push(Math.round((rating - (i - 1)) * 100)) // Partial star 31: } else { 32: fills.push(0) // Empty star 33: } 34: } 35: return fills 36: } 37: --- 38: 39:
40:
41: VERIFIED RATINGS 42: 43:

Trusted by 30,000+ workplaces

44: 45: 46:
47:
48: {Array.from({ length: 5 }).map(() => )} 49: {avgRating}+ average 50:
51:

52: Rated on Xero · Google · G2 · Capterra 53:

54:
55: 56: 57: 82:
83:
```` ## File: src/components/ReadyToJoin.astro ````astro 1: --- 2: /** 3: * ReadyToJoin - CTA section encouraging users to start a free trial 4: * 5: * Usage: 6: * 7: * 8: */ 9: import TrialButton from './TrialButton.astro' 10: 11: interface Props { 12: element: string 13: title?: string 14: description?: string 15: showPricing?: boolean 16: } 17: 18: const { 19: element, 20: title = 'Ready to join these successful businesses?', 21: description = 'Start your free trial today and see why thousands of Australian businesses trust RosterElf for their rostering and payroll.', 22: showPricing = true, 23: } = Astro.props 24: --- 25: 26:
27:
28:

{title}

29:

{description}

30:
31: 32: { 33: showPricing && ( 34: 38: View pricing 39: 40: ) 41: } 42:
43:
44:
```` ## File: src/components/RelatedAwardsGuides.astro ````astro 1: --- 2: import { ArrowRight, Award } from 'lucide-astro' 3: 4: interface RelatedAward { 5: slug: string 6: name: string 7: } 8: 9: interface Props { 10: awards: RelatedAward[] 11: background?: 'white' | 'primary' 12: } 13: 14: const { awards, background = 'white' } = Astro.props 15: 16: const bgClass = background === 'white' ? 'bg-white' : 'bg-primary-100' 17: --- 18: 19: { 20: awards.length > 0 && ( 21:
22:
23:
24: RELATED GUIDES 25:

Related award rate guides

26:

Explore other Australian Modern Award pay rate guides

27:
28: 29: 45: 46: 47: View all award guides 48: 49: 50:
51:
52: ) 53: } ```` ## File: src/components/RelatedAwardsSection.astro ````astro 1: --- 2: import { ArrowRight, Award } from 'lucide-astro' 3: import { getIndustryAwards, type AwardInfo } from '../data/awardMappings' 4: 5: interface Props { 6: industrySlug: string 7: industryName: string 8: background?: 'white' | 'primary' 9: } 10: 11: const { industrySlug, industryName, background = 'white' } = Astro.props 12: 13: const relatedAwards = getIndustryAwards(industrySlug) 14: const hasAwards = relatedAwards.length > 0 15: 16: const bgClass = background === 'white' ? 'bg-white' : 'bg-primary-100' 17: --- 18: 19: { 20: hasAwards && ( 21:
22:
23:
24: AWARD RATES 25:

Relevant awards for {industryName.toLowerCase()}

26:

Stay compliant with Australian Modern Award pay rates

27:
28: 29:
30: {relatedAwards.map((award: AwardInfo) => ( 31: 35:
36: 37:
38:
39: {award.shortName} 40: Pay rates & conditions 41:
42:
43: ))} 44:
45: 46: 47: View all award guides 48: 49: 50:
51:
52: ) 53: } ```` ## File: src/components/RelatedBlogsSection.astro ````astro 1: --- 2: /** 3: * RelatedBlogsSection - Display related blog posts on feature/industry/guide pages 4: * 5: * Usage (manual posts): 6: * 11: * 12: * Usage (auto-fetch by category): 13: * 17: * 18: * Note: Auto-fetched posts respect premiere dates (only published content shown) 19: */ 20: import { ArrowRight, Clock } from 'lucide-astro' 21: 22: interface BlogPost { 23: title: string 24: excerpt: string 25: href: string 26: image: string 27: category?: string 28: readTime?: string 29: } 30: 31: interface Props { 32: title?: string 33: subtitle?: string 34: posts?: BlogPost[] 35: category?: string // Auto-fetch from this category if no posts provided 36: background?: 'white' | 'primary' | 'gray' 37: showViewAll?: boolean 38: viewAllHref?: string 39: viewAllText?: string 40: } 41: 42: const { 43: title = 'Related insights', 44: subtitle = 'Learn more about this topic from our blog.', 45: posts: manualPosts, 46: category, 47: background = 'primary', 48: showViewAll = true, 49: viewAllHref = '/blog', 50: viewAllText = 'View all articles', 51: } = Astro.props 52: 53: // Check if a post is published (premiere date has passed or doesn't exist) 54: function isPublished(premiereDate?: string): boolean { 55: if (!premiereDate) return true 56: const now = new Date() 57: const premiere = new Date(premiereDate) 58: now.setHours(0, 0, 0, 0) 59: premiere.setHours(0, 0, 0, 0) 60: return premiere <= now 61: } 62: 63: // Auto-fetch posts if category is provided and no manual posts given 64: let posts: BlogPost[] = manualPosts || [] 65: 66: if (!manualPosts && category) { 67: // Fetch all blog posts and extract metadata 68: const blogModules = import.meta.glob('../pages/blog/*.astro', { eager: true }) as Record 69: 70: // Process blogs: filter published, filter by category, sort by date 71: const filteredBlogs = Object.entries(blogModules) 72: .filter(([_, mod]) => mod.articleMeta && isPublished(mod.premiereDate)) 73: .filter(([_, mod]) => mod.articleMeta.category === category) 74: .map(([path, mod]) => ({ 75: title: mod.articleMeta.title, 76: excerpt: mod.articleMeta.excerpt, 77: href: `/blog/${path.split('/').pop()?.replace('.astro', '')}`, 78: image: mod.articleMeta.image, 79: category: mod.articleMeta.category, 80: readTime: mod.articleMeta.readTime, 81: dateISO: mod.articleMeta.dateISO || '', 82: })) 83: .sort((a, b) => (b.dateISO || '').localeCompare(a.dateISO || '')) 84: .slice(0, 3) 85: 86: posts = filteredBlogs 87: } 88: 89: const bgClass = { 90: white: 'bg-white', 91: primary: 'bg-primary-100', 92: gray: 'bg-gray-50', 93: }[background] 94: 95: // Card background should contrast with section background 96: const cardBg = background === 'white' ? 'bg-gray-50' : 'bg-white' 97: --- 98: 99: { 100: posts.length > 0 && ( 101:
102:
103:
104:
105:

{title}

106: {subtitle &&

{subtitle}

} 107:
108: {showViewAll && ( 109: 110: {viewAllText} 111: 112: )} 113:
114: 115: 135:
136:
137: ) 138: } ```` ## File: src/components/RelatedFeaturesKB.astro ````astro 1: --- 2: /** 3: * RelatedFeaturesKB - Related features component specifically for Knowledge Base articles 4: * Features: 5: * - Contained width matching the page layout 6: * - White box container matching Related Articles style 7: * - Feature cards with hover effects 8: */ 9: import { ArrowRight } from 'lucide-astro' 10: import { getRelatedFeatures, getFeatureUrl, type FeatureInfo } from '../data/featureMappings' 11: 12: interface Props { 13: currentFeature: string 14: } 15: 16: const { currentFeature } = Astro.props 17: 18: const relatedFeatures = getRelatedFeatures(currentFeature) 19: --- 20: 21: { 22: relatedFeatures.length > 0 && ( 23:
24:
25:
26: {/* Header section */} 27:
28:

Explore related features

29:
30: 31: {/* Feature cards */} 32: 69:
70: ) 71: } ```` ## File: src/components/RelatedFeaturesSection.astro ````astro 1: --- 2: import { ArrowRight } from 'lucide-astro' 3: import { getRelatedFeatures, getFeatureUrl, type FeatureInfo } from '../data/featureMappings' 4: 5: interface Props { 6: currentFeature: string 7: background?: 'white' | 'primary' 8: } 9: 10: const { currentFeature, background = 'primary' } = Astro.props 11: 12: const relatedFeatures = getRelatedFeatures(currentFeature) 13: 14: const bgClass = background === 'white' ? 'bg-white' : 'bg-primary-100' 15: --- 16: 17: { 18: relatedFeatures.length > 0 && ( 19:
20:
21:
22: RELATED FEATURES 23:

Explore related features

24:

Discover other RosterElf features that work great together

25:
26: 27:
28: {relatedFeatures.map((feature: FeatureInfo) => ( 29: 33:
34: {feature.name} 35: {feature.category} 36:
37: 38:
39: ))} 40:
41: 42: 43: View all features 44: 45: 46:
47:
48: ) 49: } ```` ## File: src/components/RelatedGuidesSection.astro ````astro 1: --- 2: import { ArrowRight } from 'lucide-astro' 3: import type { AstroComponentFactory } from 'astro/runtime/server/index.js' 4: import { readFile } from 'node:fs/promises' 5: import { join } from 'node:path' 6: 7: interface Guide { 8: href: string 9: title: string 10: description: string 11: icon: AstroComponentFactory 12: linkText?: string 13: } 14: 15: interface Props { 16: title?: string 17: subtitle?: string 18: guides: Guide[] 19: background?: 'white' | 'primary' 20: maxWidth?: string 21: } 22: 23: /** 24: * Check if a blog post has a future premiere date 25: */ 26: async function hasFuturePremiereDate(blogSlug: string): Promise { 27: try { 28: const filePath = join(process.cwd(), 'src/pages/blog', `${blogSlug}.astro`) 29: const content = await readFile(filePath, 'utf-8') 30: 31: // Extract premiere date from content 32: const premiereDateMatch = content.match(/premiereDate\s*=\s*['"]([^'"]+)['"]/) 33: if (!premiereDateMatch) return false 34: 35: const premiereDate = new Date(premiereDateMatch[1]) 36: const now = new Date() 37: 38: // Compare dates at midnight 39: now.setHours(0, 0, 0, 0) 40: premiereDate.setHours(0, 0, 0, 0) 41: 42: return premiereDate > now 43: } catch { 44: // If file doesn't exist or can't be read, assume it's not a blog post or is published 45: return false 46: } 47: } 48: 49: /** 50: * Filter out guides with future premiere dates (blog posts only) 51: */ 52: async function filterPublishedGuides(guides: Guide[]): Promise { 53: const results = await Promise.all( 54: guides.map(async (guide) => { 55: // Only check blog posts (href starts with /blog/) 56: if (!guide.href.startsWith('/blog/')) return { guide, isPublished: true } 57: 58: // Extract slug from href 59: const slug = guide.href.replace('/blog/', '') 60: const isFuture = await hasFuturePremiereDate(slug) 61: 62: return { guide, isPublished: !isFuture } 63: }) 64: ) 65: 66: return results.filter((r) => r.isPublished).map((r) => r.guide) 67: } 68: 69: const { title = 'Related guides', subtitle = 'More resources to help you.', guides, background = 'primary', maxWidth = 'max-w-7xl' } = Astro.props 70: 71: // Filter out unpublished blog posts 72: const publishedGuides = await filterPublishedGuides(guides) 73: 74: const bgClass = background === 'white' ? 'bg-white' : 'bg-primary-100' 75: --- 76: 77: { 78: publishedGuides.length > 0 && ( 79:
80:
81:
82:

{title}

83:

{subtitle}

84:
85:
86: {publishedGuides.map((guide) => { 87: const Icon = guide.icon 88: return ( 89: 93:
94: 95:
96:

{guide.title}

97:

{guide.description}

98: 99: {guide.linkText || 'Learn more'} 100: 101:
102: ) 103: })} 104:
105:
106:
107: ) 108: } ```` ## File: src/components/RelatedIndustriesSection.astro ````astro 1: --- 2: import { ArrowRight } from 'lucide-astro' 3: import { getRelatedIndustries, type IndustryInfo } from '../data/industryMappings' 4: 5: interface Props { 6: currentIndustry: string 7: background?: 'white' | 'primary' 8: } 9: 10: const { currentIndustry, background = 'primary' } = Astro.props 11: 12: const relatedIndustries = getRelatedIndustries(currentIndustry) 13: 14: const bgClass = background === 'white' ? 'bg-white' : 'bg-primary-100' 15: --- 16: 17: { 18: relatedIndustries.length > 0 && ( 19:
20:
21:
22: RELATED INDUSTRIES 23:

Explore similar industries

24:

See how RosterElf helps other businesses like yours

25:
26: 27:
28: {relatedIndustries.map((industry: IndustryInfo) => ( 29: 33: {industry.name} 34: 35: 36: ))} 37:
38: 39: 40: View all industries 41: 42: 43:
44:
45: ) 46: } ```` ## File: src/components/RelatedProductUpdates.astro ````astro 1: --- 2: import { ArrowRight, Calendar, Sparkles } from 'lucide-astro' 3: 4: interface ProductUpdate { 5: title: string 6: excerpt: string 7: href: string 8: date: string 9: tag: string 10: } 11: 12: interface Props { 13: updates: ProductUpdate[] 14: background?: 'white' | 'primary' 15: maxWidth?: string 16: chip?: string 17: title?: string 18: description?: string 19: } 20: 21: const { 22: updates, 23: background = 'white', 24: maxWidth = 'max-w-7xl', 25: chip = 'MORE UPDATES', 26: title = 'Other recent product updates', 27: description = "Discover the latest features and improvements we've shipped", 28: } = Astro.props 29: 30: const bgClass = background === 'white' ? 'bg-white' : 'bg-primary-100' 31: --- 32: 33: { 34: updates.length > 0 && ( 35:
36: 74:
75: ) 76: } ```` ## File: src/components/RelatedResourcesGrid.astro ````astro 1: --- 2: /** 3: * RelatedResourcesGrid - Tabbed Related Resources Component 4: * 5: * Displays related guides, insights, and templates for free tool pages. 6: * Uses tabbed interface for switching between resource types. 7: * 8: * Props: 9: * - toolId: string - The tool slug to fetch related resources for 10: * - background: "white" | "primary" (default: "white") 11: */ 12: 13: import { getToolRelatedResources, type RelatedResource } from '../data/freeToolRelatedResources' 14: import { BookOpen, Lightbulb, FileText, ArrowRight } from 'lucide-astro' 15: 16: interface Props { 17: toolId: string 18: background?: 'white' | 'primary' 19: } 20: 21: const { toolId, background = 'white' } = Astro.props 22: 23: // Get related resources for this tool 24: const resources = getToolRelatedResources(toolId) 25: 26: // Generate unique ID for this instance 27: const instanceId = Math.random().toString(36).substring(7) 28: 29: // Tab configuration 30: const tabs = [ 31: { id: 'guides', label: 'Guides', icon: BookOpen, items: resources?.guides || [] }, 32: { id: 'insights', label: 'Insights', icon: Lightbulb, items: resources?.insights || [] }, 33: { id: 'templates', label: 'Templates', icon: FileText, items: resources?.templates || [] }, 34: ] 35: 36: // Only render if we have resources 37: const hasResources = tabs.some((tab) => tab.items.length > 0) 38: --- 39: 40: { 41: hasResources && ( 42:
43:
44: {/* Header */} 45:
46:

Related resources

47:

Explore guides, insights, and templates to help you get more from this tool.

48:
49: 50: {/* Tabs */} 51:
52: {tabs.map((tab, index) => { 53: const IconComponent = tab.icon 54: const hasItems = tab.items.length > 0 55: return ( 56: 77: ) 78: })} 79:
80: 81: {/* Content Panels */} 82: 132:
133:
134: ) 135: } 136: 137: ```` ## File: src/components/RelatedSupportArticles.astro ````astro 1: --- 2: import { ArrowRight, BookOpen } from 'lucide-astro' 3: 4: interface SupportArticle { 5: title: string 6: excerpt: string 7: href: string 8: category?: string 9: } 10: 11: interface Props { 12: articles: SupportArticle[] 13: background?: 'white' | 'primary' 14: maxWidth?: string 15: } 16: 17: const { articles, background = 'white', maxWidth = 'max-w-7xl' } = Astro.props 18: 19: const bgClass = background === 'white' ? 'bg-white' : 'bg-primary-100' 20: --- 21: 22: { 23: articles.length > 0 && ( 24:
25:
26:
27: HELP & SUPPORT 28:

Related support articles

29:

Step-by-step guides to help you get started

30:
31: 32: 51: 52: 53: Browse all support articles 54: 55: 56:
57:
58: ) 59: } ```` ## File: src/components/ResponsiveLink.astro ````astro 1: --- 2: interface Props { 3: href: string 4: mobileText: string 5: desktopText: string 6: target?: string 7: rel?: string 8: class?: string 9: } 10: 11: const { href, mobileText, desktopText, target, rel, class: className } = Astro.props 12: --- 13: 14: 15: {mobileText} 16: 17: ```` ## File: src/components/RestaurantAwardCalculator.astro ````astro 1: --- 2: // Restaurant Award Rate Calculator Component 3: // Data from 2025 Restaurant Industry Award 2020 [MA000119] rates 4: 5: import { AlertTriangle, FileText, Clock, CheckCircle, ChevronDown, User, Calculator } from 'lucide-astro' 6: import TrialButton from './TrialButton.astro' 7: 8: const ratesData = { 9: permanent: { 10: Introductory: 24.28, 11: 'Level 1': 24.95, 12: 'Level 2': 25.85, 13: 'Level 3': 26.7, 14: 'Level 4': 28.12, 15: 'Level 5': 29.88, 16: 'Level 6': 30.68, 17: }, 18: casual: { 19: Introductory: 30.35, 20: 'Level 1': 31.19, 21: 'Level 2': 32.31, 22: 'Level 3': 33.38, 23: 'Level 4': 35.15, 24: 'Level 5': 37.35, 25: 'Level 6': 38.35, 26: }, 27: } 28: 29: // Fixed award rules - Restaurant Award has NO evening or late night penalties 30: const awardRules = [ 31: { 32: id: 'ordinary', 33: name: 'Ordinary hours (Mon-Fri)', 34: days: ['MON', 'TUE', 'WED', 'THU', 'FRI'], 35: startTime: '07:00', 36: endTime: '19:00', 37: penaltyMultiplier: { permanent: 1.0, casual: 1.0 }, 38: }, 39: { 40: id: 'saturday', 41: name: 'Saturday (all day)', 42: days: ['SAT'], 43: startTime: '00:00', 44: endTime: '00:00', 45: penaltyMultiplier: { permanent: 1.5, casual: 1.75 }, 46: }, 47: { 48: id: 'sunday', 49: name: 'Sunday (all day)', 50: days: ['SUN'], 51: startTime: '00:00', 52: endTime: '00:00', 53: penaltyMultiplier: { permanent: 1.75, casual: 2.0 }, 54: }, 55: { 56: id: 'publicholiday', 57: name: 'Public holiday', 58: days: ['HOL'], 59: startTime: '00:00', 60: endTime: '00:00', 61: penaltyMultiplier: { permanent: 2.5, casual: 2.75 }, 62: }, 63: ] 64: --- 65: 66:
67:
68:
AWARD RATE ESTIMATOR
69:

See how RosterElf interprets the Restaurant Award

70:

71: This is an educational example showing how the Restaurant Award penalty rates work. It demonstrates how RosterElf automatically calculates correct pay rates based on classification level, 72: employment type, and shift times. 73:

74:
75: 76: 77:
78:
79: 80:
81: Important: This is an estimator for demonstration purposes only. Do not use these calculations for actual payroll without verifying against the 82: official Fair Work MA000119 summary 88: and consulting your Award obligations. 89:
90:
91:
92: 93: 94:
95:
96: 97:
98: 99:
100:
101: 102:
103: 110:
111:
112: 113: 114:
115: 116:
117:
118: 119:
120: 132:
133:
134:
135:
136: 137: 138:
139:
140:
141:
Base ordinary rate
142:
Mon-Fri, standard hours
143:
144:
145:
146: $ 147: 24.95 148: /hr 149:
150:
151:
152:
153: 154: 155:
156:

157: 158: Restaurant Award penalty rates 159:

160: 161:
162: 163:
164:
165: 166: 167:
168:

169: 170: Example weekly cost (38 hours) 171:

172: 173:
174: 175:
176: 177:
178: Example total: 179: $1,025.29 180:
181:
182: 183: 184:
185:
186:
187: 188:
189:

Example only - not for payroll use

190:

This is a demonstration of how RosterElf calculates award-compliant rates.

191:
192:
193: 203:
204: 205:
206:
207:
208:

The actual cost for your employees will depend on:

209: 210:
    211:
  • Their specific classification level and employment type
  • 212:
  • Actual hours worked and shift times
  • 213:
  • Any additional allowances, overtime, or enterprise agreement provisions
  • 214:
  • Current award rates (which change annually in July)
  • 215:
216: 217:

For accurate payroll calculations, always:

218: 219:
    220:
  1. 221: Verify current rates with the official Fair Work MA000119 summary 227:
  2. 228:
  3. Confirm your employees' correct award coverage and classification
  4. 229:
  5. Use award interpretation software or consult a payroll professional
  6. 230:
  7. Review your specific enterprise agreement (if applicable)
  8. 231:
232: 233:

Do not rely on this example for actual wage payments.

234:
235:
236:
237:
238: 239: 240:
241: 242:
243:

Stop calculating penalty rates manually

244:

Let RosterElf handle award compliance automatically

245: 246:

247: Manual award calculations are time-consuming and error-prone. One mistake can lead to underpayments, compliance issues, and Fair Work penalties. RosterElf's award interpretation engine does 248: the work for you. 249:

250: 251:
252: 253:
254: 255:
256: 257: 258: No credit card required 259: 260: 261: 262: Full access 263: 264: 265: 266: 24/7 support 267: 268:
269:
270: 271: 272:
273:

How RosterElf automates award calculations

274: 275:
276: 277:
278:
279:
1
280: 281:
282:
Create pay templates
283:

284: Create pay templates for each classification level by adding award-compliant base rates and penalty multipliers. Once configured, RosterElf automatically applies the correct template to 285: each shift based on the employee's classification, shift timing, and employment type. 286:

287: Award interpretation → 288:
289: 290: 291:
292:
293:
2
294: 295:
296:
Define rate rules
297:

298: Configure when different penalty rates apply (weekends, public holidays). The system automatically detects which rate to use based on shift times and days. 299:

300: Penalty rates guide → 301:
302: 303: 304:
305:
306:
3
307: 308:
309:
Auto-apply to shifts
310:

311: Every rostered shift automatically calculates the correct pay rate based on the employee's classification, employment type, and shift timing. No manual work required. 312:

313: Payroll integration → 314:
315:
316: 317: 318:
319:

Learn more:

320: 327:
328:
329:
330:
331: 332: 557: 558: ```` ## File: src/components/ReviewCarousel.astro ````astro 1: --- 2: import { Star } from 'lucide-astro' 3: 4: interface Review { 5: platform: 'google' | 'g2' | 'capterra' | 'xero' 6: platformLogo: string 7: rating: number 8: text: string 9: author: string 10: authorImage?: string 11: authorInitials?: string 12: date: string 13: } 14: 15: interface Props { 16: chip?: string 17: title?: string 18: description?: string 19: ctaText?: string 20: ctaUrl?: string 21: reviews?: Review[] 22: background?: 'primary' | 'white' 23: } 24: 25: const defaultReviews: Review[] = [ 26: { 27: platform: 'google', 28: platformLogo: '/images/logos/google.svg', 29: rating: 5, 30: text: "We are extremely happy with Roster Elf, it's a great improvement on the previous system we were using. Sean and all the staff have been fantastic, really know their stuff and make using RosterElf a pleasure.", 31: author: 'Andrew Nathan', 32: authorInitials: 'AN', 33: date: 'November 13, 2025', 34: }, 35: { 36: platform: 'google', 37: platformLogo: '/images/logos/google.svg', 38: rating: 5, 39: text: 'Sean was an amazing help, very patient and thorough.', 40: author: 'Monica Van De Laak', 41: authorInitials: 'MV', 42: date: 'October 16, 2025', 43: }, 44: { 45: platform: 'g2', 46: platformLogo: '/images/logos/g2-logo.webp', 47: rating: 5, 48: text: 'I can see my roster, enter availability, put leave in advance and clock on and off easily.', 49: author: 'Mary C.', 50: authorInitials: 'MC', 51: date: 'October 13, 2025', 52: }, 53: { 54: platform: 'google', 55: platformLogo: '/images/logos/google.svg', 56: rating: 5, 57: text: 'Really detailed and helpful. First time user of a rostering software and I was provided with clear and easy to follow instructions with the promise of being available for any further questions or help that I might need in the future. Would definitely recommend', 58: author: 'Partap Singh Thind', 59: authorInitials: 'PT', 60: date: 'December 05, 2025', 61: }, 62: { 63: platform: 'google', 64: platformLogo: '/images/logos/google.svg', 65: rating: 5, 66: text: 'Very easy to use and navigate. The support team is always quick to respond and helpful with any queries.', 67: author: 'Sarah Johnson', 68: authorInitials: 'SJ', 69: date: 'September 28, 2025', 70: }, 71: { 72: platform: 'g2', 73: platformLogo: '/images/logos/g2-logo.webp', 74: rating: 5, 75: text: 'Great tool for managing staff rosters and timesheets. Has made our scheduling much more efficient.', 76: author: 'David L.', 77: authorInitials: 'DL', 78: date: 'August 15, 2025', 79: }, 80: { 81: platform: 'google', 82: platformLogo: '/images/logos/google.svg', 83: rating: 5, 84: text: 'Excellent rostering software! The drag and drop feature makes creating weekly schedules a breeze. Our team loves the mobile app for checking their shifts.', 85: author: 'James Mitchell', 86: authorInitials: 'JM', 87: date: 'November 28, 2025', 88: }, 89: { 90: platform: 'capterra', 91: platformLogo: '/images/logos/capterra.svg', 92: rating: 5, 93: text: 'RosterElf has transformed how we manage our hospitality staff. The award interpretation feature alone saves us hours every pay period.', 94: author: 'Emma Richardson', 95: authorInitials: 'ER', 96: date: 'October 22, 2025', 97: }, 98: { 99: platform: 'google', 100: platformLogo: '/images/logos/google.svg', 101: rating: 5, 102: text: 'Finally found a rostering solution that understands Australian workplace requirements. The Fair Work compliance features give us peace of mind.', 103: author: 'Michael Chen', 104: authorInitials: 'MC', 105: date: 'September 15, 2025', 106: }, 107: { 108: platform: 'g2', 109: platformLogo: '/images/logos/g2-logo.webp', 110: rating: 5, 111: text: 'The integration with Xero is smooth. Timesheets flow directly into payroll without any manual data entry. Highly recommend for any small business.', 112: author: 'Rachel K.', 113: authorInitials: 'RK', 114: date: 'August 30, 2025', 115: }, 116: ] 117: 118: const { 119: chip = 'WHAT OTHERS SAY', 120: title = 'Reviews from our customers', 121: description = 'Read what our clients have to say about us', 122: ctaText = 'See all reviews', 123: ctaUrl = '/why-rosterelf/online-reviews', 124: reviews = defaultReviews, 125: background = 'primary', 126: } = Astro.props 127: 128: const bgClass = background === 'primary' ? 'bg-primary-100' : 'bg-white' 129: --- 130: 131: 232: 233: 311: 312: ```` ## File: src/components/ReviewMethodologyCallout.astro ````astro 1: --- 2: import { FileText, ArrowRight } from 'lucide-astro' 3: 4: interface Props { 5: inline?: boolean 6: background?: 'white' | 'primary' 7: } 8: 9: const { inline = false, background = 'white' } = Astro.props 10: const bgClass = background === 'primary' ? 'bg-primary-100' : 'bg-white' 11: --- 12: 13: { 14: inline ? ( 15: 27: ) : ( 28:
29: 41:
42: ) 43: } ```` ## File: src/components/ReviewsWithComments.astro ````astro 1: --- 2: import { Star, HelpCircle } from 'lucide-astro' 3: 4: interface Props { 5: review: { 6: initials: string 7: name: string 8: date: string 9: quote: string 10: logo?: 'xero' | 'g2' | 'capterra' 11: } 12: content: { 13: chip: string 14: heading: string 15: description: string 16: linkText?: string 17: linkHref?: string 18: } 19: reversed?: boolean 20: } 21: 22: const { review, content, reversed = false } = Astro.props 23: --- 24: 25:
*:first-child]:order-2' : ''}`}> 26: 27:
28:
29:
30:
{review.initials}
31:
32:

{review.name}

33:

{review.date}

34:
35:
36: {review.logo === 'xero' && Reviewed on Xero} 37: {review.logo === 'g2' && Reviewed on G2} 38: {review.logo === 'capterra' && Reviewed on Capterra} 39:
40:
41: 42: 43: 44: 45: 46:
47:

"{review.quote}"

48:
49: 50: 51:
52: {content.chip} 53:

{content.heading}

54:

{content.description}

55: { 56: content.linkHref && content.linkText && ( 57: 58: 59: {content.linkText} 60: 61: ) 62: } 63:
64:
```` ## File: src/components/ROICalculator.astro ````astro 1: --- 2: import TrialButton from './TrialButton.astro' 3: 4: interface Props { 5: chip?: string 6: title?: string 7: description?: string 8: background?: 'primary' | 'white' 9: currencySymbol?: string 10: currencyLocale?: string 11: defaultWage?: number 12: } 13: 14: const { 15: chip = 'ROI CALCULATOR', 16: title = 'Calculate your rostering savings', 17: description = 'See how much time and money your business could save with RosterElf rostering software.', 18: background = 'white', 19: currencySymbol = '$', 20: currencyLocale = 'en-AU', 21: defaultWage = 45, 22: } = Astro.props 23: 24: const bgClass = background === 'primary' ? 'bg-primary-100' : 'bg-white' 25: --- 26: 27:
28:
29:
30: {chip} 31:

{title}

32:

{description}

33:
34: 35:
36: 37:
38:

Your current rostering

39: 40:
41: 42: 50:
51: 52:
53: 54: 62:
63: 64:
65: 66: 74:
75: 76:

Based on 70% time reduction with automated rostering

77:
78: 79: 80:
81:

Your potential savings

82: 83:
84:
85: Time saved per week 86: 3.5 hours 87:
88: 89:
90: Annual time saved 91: 182 hours 92:
93: 94:
95: Annual cost savings 96: {currencySymbol}8,190 97:
98:
99: 100:
101: 102:

No credit card required

103:
104:
105:
106:
107:
108: 109: ```` ## File: src/components/SimpleCTA.astro ````astro 1: --- 2: import TrialButton from './TrialButton.astro' 3: 4: interface Props { 5: title: string 6: description: string 7: } 8: 9: const { title, description } = Astro.props 10: --- 11: 12:
13:
14:
15:

{title}

16:

{description}

17: 18:
19:
20:
```` ## File: src/components/SoftwareFeatureSchema.astro ````astro 1: --- 2: /** 3: * SoftwareFeatureSchema - Generates schema.org SoftwareApplication markup for feature pages 4: * 5: * This component adds structured data to help search engines understand 6: * that this page describes a specific feature of RosterElf software. 7: */ 8: import { ratingsData } from '../data/ratingsData' 9: 10: interface Props { 11: name: string // Feature name e.g., "Rostering Software", "Time & Attendance" 12: description: string // Page meta description 13: url: string // Canonical URL path e.g., "/features/rostering-software" 14: image?: string // Hero image URL 15: datePublished?: string // ISO date when feature was first published 16: dateModified?: string // ISO date when feature was last updated 17: applicationSubCategory?: string // Optional subcategory override, defaults to "Workforce Management" 18: featureList?: string[] // Optional feature list override, defaults to core features 19: price?: string // Override price, defaults to '4.00' (AUD) 20: priceCurrency?: string // Override currency, defaults to 'AUD' 21: eligibleRegion?: string // Override region, defaults to 'Australia' 22: } 23: 24: const { name, description, url, image, datePublished, dateModified, applicationSubCategory, featureList, price: offerPrice = '4.00', priceCurrency = 'AUD', eligibleRegion = 'Australia' } = Astro.props 25: 26: const softwareSchema = { 27: '@context': 'https://schema.org', 28: '@type': 'SoftwareApplication', 29: name: `RosterElf ${name}`, 30: description: description, 31: url: `https://www.rosterelf.com${url}`, 32: ...(image && { image: `https://www.rosterelf.com${image}` }), 33: ...(datePublished && { datePublished }), 34: ...(dateModified && { dateModified }), 35: applicationCategory: 'BusinessApplication', 36: applicationSubCategory: applicationSubCategory || 'Workforce Management', 37: operatingSystem: 'Web, iOS, Android', 38: provider: { 39: '@type': 'Organization', 40: name: 'RosterElf', 41: url: 'https://www.rosterelf.com', 42: logo: 'https://www.rosterelf.com/images/logos/rosterelf-logo.svg', 43: }, 44: aggregateRating: { 45: '@type': 'AggregateRating', 46: ratingValue: String(ratingsData.aggregate.averageRating), 47: bestRating: '5', 48: worstRating: '1', 49: ratingCount: String(ratingsData.aggregate.totalReviews), 50: }, 51: offers: { 52: '@type': 'Offer', 53: price: offerPrice, 54: priceCurrency: priceCurrency, 55: priceValidUntil: '2026-12-31', 56: eligibleRegion: { 57: '@type': 'Country', 58: name: eligibleRegion, 59: }, 60: availability: 'https://schema.org/OnlineOnly', 61: }, 62: featureList: featureList || ['Drag-and-drop rostering', 'Auto-scheduling', 'Time and attendance tracking', 'Award interpretation', 'Payroll integration', 'Mobile app access'], 63: } 64: --- 65: 66: ```` ## File: src/components/TrustedBySection.astro ````astro 1: --- 2: interface Props { 3: title?: string 4: description?: string 5: background?: 'primary' | 'white' 6: } 7: 8: const { 9: title = 'Trusted by Australian businesses', 10: description = 'From local cafes to national retail chains, thousands of businesses rely on RosterElf for rostering, HR and payroll.', 11: background = 'white', 12: } = Astro.props 13: 14: const bgClass = background === 'primary' ? 'bg-primary-100' : 'bg-white' 15: const fadeFromClass = background === 'primary' ? 'from-primary-100' : 'from-white' 16: 17: // Logo config with individual scale adjustments for visual weight normalization 18: // scale: 1 = baseline, <1 = reduce for heavy logos, >1 = increase for thin logos 19: // yOffset: vertical adjustment for wordmark baseline alignment (positive = down) 20: const logos = [ 21: { src: '/images/clients/inspire-care-sa-logo.webp', alt: 'Inspire Care SA', scale: 1.1, yOffset: 0 }, 22: { src: '/images/clients/pressed-earth-logo.webp', alt: 'Pressed Earth', scale: 0.85, yOffset: 0 }, 23: { src: '/images/clients/toowoomba-catholic-logo.webp', alt: 'Toowoomba Catholic Kindergartens', scale: 1.0, yOffset: 0 }, 24: { src: '/images/clients/cellarbration-logo.webp', alt: 'Cellarbrations', scale: 1.05, yOffset: 2 }, 25: { src: '/images/clients/iga-logo.webp', alt: 'IGA', scale: 0.8, yOffset: 0 }, 26: { src: '/images/clients/the-coffee-club-logo.webp', alt: 'The Coffee Club', scale: 0.85, yOffset: 0 }, 27: { src: '/images/clients/glouster-park-logo.webp', alt: 'Gloucester Park', scale: 1.0, yOffset: 0 }, 28: { src: '/images/clients/bagel-os-logo.webp', alt: "Bagel O's", scale: 0.9, yOffset: 0 }, 29: { src: '/images/clients/bush-kids-childcare-logo.webp', alt: 'Bush Kids Childcare', scale: 1.0, yOffset: 0 }, 30: { src: '/images/clients/the-embassy-logo.webp', alt: 'The Embassy', scale: 0.95, yOffset: 0 }, 31: ] 32: --- 33: 34:
35:
36:
37:

{title}

38:

{description}

39:
40: 41: 42: 81:
82:
83: 84: ```` ## File: src/components/VideoSchema.astro ````astro 1: --- 2: /** 3: * VideoSchema - Generates schema.org VideoObject markup for video pages 4: * 5: * This component adds structured data to help Google show video rich results 6: * in search. Required for videos to appear in Google Video search and carousels. 7: * 8: * @see https://developers.google.com/search/docs/appearance/structured-data/video 9: */ 10: 11: interface Props { 12: name: string // Video title 13: description: string // Video description 14: videoId: string // YouTube video ID 15: uploadDate?: string // ISO 8601 datetime (e.g., "2024-01-15T00:00:00+10:00") 16: duration?: string // ISO 8601 duration (e.g., "PT2M30S" for 2 min 30 sec) 17: } 18: 19: const { name, description, videoId, uploadDate = '2024-01-01T00:00:00+10:00', duration } = Astro.props 20: 21: const videoSchema = { 22: '@context': 'https://schema.org', 23: '@type': 'VideoObject', 24: name: name, 25: description: description, 26: thumbnailUrl: [`https://img.youtube.com/vi/${videoId}/maxresdefault.jpg`, `https://img.youtube.com/vi/${videoId}/sddefault.jpg`, `https://img.youtube.com/vi/${videoId}/hqdefault.jpg`], 27: uploadDate: uploadDate, 28: ...(duration && { duration: duration }), 29: contentUrl: `https://www.youtube.com/watch?v=${videoId}`, 30: embedUrl: `https://www.youtube.com/embed/${videoId}`, 31: publisher: { 32: '@type': 'Organization', 33: name: 'RosterElf', 34: url: 'https://www.rosterelf.com', 35: logo: { 36: '@type': 'ImageObject', 37: url: 'https://www.rosterelf.com/images/logos/rosterelf-logo.svg', 38: }, 39: }, 40: } 41: --- 42: 43: 204: 205: 206: 207: 208: 225: 226: 227: 228: 229: { 230: enableAnalytics && ( 231: <> 232: {/* Google Tag Manager (noscript) */} 233: